main.html

Next Page
Negus Live Linux Series Ajax Construction Kit: Building Plug-and-Play Ajax Applications
Negus Live Linux Series Ajax Construction Kit: Building Plug-and-Play Ajax Applications
by Michael Morrison
Publisher: Prentice Hall
Pub Date: June 29, 2007
Print ISBN-10: 0-13-235008-4
Print ISBN-13: 978-0-13-235008-2
Pages: 312
Table of Contents
| Index
Overview

Supercharge Your Sites with Ajax Right Now...No Scripting Expertise Needed!

You've heard how great Ajax is--how it can help make your Web sites more usable, more interactive, more responsive, more successful. Ajax Construction Kit lets you put Ajax to work right now, even if you've never written a script! Just learn a few essentials, check out a few examples, then run the live CD and discover all the plug-and-play code you need to hit the ground running. Ajax Construction Kit's built-in applications work right out of the box. And with easy guidance from Michael Morrison, you'll gradually deepen your understanding--learn how to customize, extend, and reuse these applications--and even build skills for creating new ones. Walk away an expert.

Use Ajax Construction Kit's ten complete applications to

  • Dynamically load Web data

  • Dynamically populate lists

  • Tap into RSS news feeds

  • Use AutoComplete to reduce input errors

  • Create more responsive GUIs with real-time validation

  • Build a killer interface for viewing images

  • Present information or advertising with slick pop-ups

  • Provide an up-to-the-minute weather forecast

  • Build an e-commerce product shipping calculator

  • Add ratings tools to your site

And more...

CD-ROM Includes

  • Your complete Ajax projects: Run the Ajax projects (HTML, JavaScript, and PHP source code) that are included on the CD from your Windows, Mac OS X, or Linux system.

  • Your complete Ajax environment: Boot the CD as an Ubuntu Linux live CD to immediately begin working with the Ajax projects (no setup required).

  • Ready-to-run tools on the CD include the XAMPP Web server, Firefox Web browser, and Bluefish HTML editor.

System Requirements:

  • Platform: Windows, Linux, Mac (OS X or higher)

  • Processor: Intel-based processor (Pentium or higher)

  • Memory: 128 MB RAM or more

  • Disk space: None required; USB thumb drive optional to store data

  • Optical drive: CD reader

Negus Live Linux Series

Your Practical, Hands-On Guides to Getting Real Results with Free Software

Add the free software and examples from the book's CD to your Windows, Mac OS X, or Linux system to follow along with the projects described in the book. Or boot the CD directly to use a complete, prepackaged set of free software tools to play, display, and modify those projects. Start as a novice, by trying out examples...and finish with professional Ajax-enabled Web content!

SERIES EDITOR CHRISTOPHER NEGUS is the bestselling author of the Red Hat Linux Bible series, Linux Toys series, and this series's flagship title, Linux Live CDs.

Introduction 1

Part I Ajax Boot Camp

1 Ajax and a Brave New World Wide Web 9

2 Inside an Ajax Application 25

Part II Building Real-World Ajax Applications

3 Dynamically Loading Web Data: An XML E-Book Viewer 49

4 Using Ajax to Dynamically Populate Lists: A Stock Picker 75

5 Tapping into RSS News Feeds 97

6 Reading the User's Mind with Auto-Complete 121

7 Creating Responsive GUIs with Real-Time Validation 139

8 A Killer Interface for Image Viewing 159

9 Presenting Information with Slick Popups 171

10 Forecasting the Weather with Ajax 189

11 Building an Ajax Shipping Calculator 205

12 Adding an Ajax-Powered Rating System to Your Site 231

Part III Appendices

Appendix A The Past, Present, and Future of Ajax 257

Appendix B A Quick and Dirty XMLHttpRequest Reference 261

Appendix C Using the Live Linux CD 271

Next Page


toc.html

Negus Live Linux Series Ajax Construction Kit: Building Plug-and-Play Ajax Applications - Graphically Rich Book
Negus Live Linux Series Ajax Construction Kit: Building Plug-and-Play Ajax Applications
by Michael Morrison
Publisher: Prentice Hall
Pub Date: June 29, 2007
Print ISBN-10: 0-13-235008-4
Print ISBN-13: 978-0-13-235008-2
Pages: 312
Table of Contents
| Index
Copyright
Negus Live Linux Series
Acknowledgments
About the Author
Introduction
The Audience for This Book
The Organization of This Book
About the CD-ROM for This Book
What You Need to Use This Book
Part I: Ajax Boot Camp
Chapter 1. Ajax and a Brave New World Wide Web
Dining with Ajax
Ajax, Sting, and Asynchronicity
To Reload, or Not Reload
What Exactly Is Ajax?
Real-World Ajax
Ajax Isn't for Everything
The Shipping Charge Calculator Revisited
Summary
Chapter 2. Inside an Ajax Application
The Nuts and Bolts of Ajax
The Ajax Request Lifecycle
Getting to Know the Ajax Toolkit
Dismantling the E-Book Viewer
Customizing the E-Book Viewer
Summary
Part II: Building Real-World Ajax Applications
Chapter 3. Dynamically Loading Web Data: An XML E-Book Viewer
The Challenge: Loading Data in Smaller Chunks
The Design: Designing an XML E-Book Viewer
Putting Together the E-Book Viewer
Testing Booker
Giving Booker an Extreme Ajax Makeover
Summary
Chapter 4. Using Ajax to Dynamically Populate Lists: A Stock Picker
The Challenge: Displaying Selected Stock Information
The Design: Designing a Stock Picker
Putting Together the Stock Picker
Testing Picker
Giving Picker an Extreme Ajax Makeover
Summary
Chapter 5. Tapping into RSS News Feeds
The Challenge: Querying News Feeds Dynamically
The Design: Designing a News Feed Application
Putting Together the News Feeder Application
Testing the News Feeder
Giving News Feeder an Extreme Ajax Makeover
Summary
Chapter 6. Reading the User's Mind with Auto-Complete
The Challenge: Anticipating Data Entry
The Design: Designing an Auto-Complete Application
Putting Together the Completer Application
Testing Completer
Giving Completer an Extreme Ajax Makeover
Summary
Chapter 7. Creating Responsive GUIs with Real-Time Validation
The Challenge: Checking User Input in Real Time
The Design: Designing a Validator Application
Putting Together the Validator Application
Testing Validator
Giving Validator an Extreme Ajax Makeover
Summary
Chapter 8. A Killer Interface for Image Viewing
The Challenge: Loading Images Dynamically
The Design: Designing a Dynamic Image Viewer
Putting Together the Imaginator Application
Testing Imaginator
Giving Imaginator an Extreme Ajax Makeover
Summary
Chapter 9. Presenting Information with Slick Popups
The Challenge: Creating Linked Popups
The Design: Designing an Information Popup Application
Putting Together the Informer Application
Testing Informer
Giving Informer an Extreme Ajax Makeover
Summary
Chapter 10. Forecasting the Weather with Ajax
The Challenge: Gathering Dynamic Weather Information
The Design: Designing a Weather Forecaster
Putting Together the Forecaster Application
Testing Forecaster
Giving Forecaster an Extreme Ajax Makeover
Summary
Chapter 11. Building an Ajax Shipping Calculator
The Challenge: Retrieving Live Shipping Charges
The Design: Designing a Shipper Application
The Client Request
The Server Response
Making Sense of the Client-to-Server Conversation
Putting Together the Shipper Application
The Shipper Web Page
The Shipper Server Script
Testing Shipper
Giving Shipper an Extreme Ajax Makeover
Summary
Chapter 12. Adding an Ajax-Powered Rating System to Your Site
The Challenge: Adding Ratings to a Web Site
The Design: Designing a Rater Application
Putting Together the Rater Application
Testing Rater
Giving Rater an Extreme Ajax Makeover
Summary
Part III: Appendices
Appendix A. The Past, Present, and Future of Ajax
The Road to Ajax
The Ajax Boom
What's Next for Ajax?
Appendix B. A Quick and Dirty XMLHttpRequest Reference
Methods
Properties
Events
Appendix C. Using the Live Linux CD
Inside the Live CD
Running the Live CD
Running the Live CD Directly on a Windows PC
Running the Live CD Directly on a Mac PC
Running the Live CD in Other Ways
Index


copyrightpg.html

Copyright

Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in this book, and the publisher was aware of a trademark claim, the designations have been printed with initial capital letters or in all capitals.

The author and publisher have taken care in the preparation of this book, but make no expressed or implied warranty of any kind and assume no responsibility for errors or omissions. No liability is assumed for incidental or consequential damages in connection with or arising out of the use of the information or programs contained herein.

The publisher offers excellent discounts on this book when ordered in quantity for bulk purchases or special sales, which may include electronic versions and/or custom covers and content particular to your business, training goals, marketing focus, and branding interests. For more information, please contact:

U.S. Corporate and Government Sales
(800)382-3419
corpsales@pearsontechgroup.com

For sales outside the United States, please contact:

International Sales
international@pearsoned.com

Visit us on the Web: www.prenhallprofessional.com

Library of Congress Cataloging-in-Publication Data

Morrison, Michael, 1970-
Ajax construction kit : building plug-and-play Ajax applications / Michael Morrison.
p. cm.
ISBN 978-0-13-235008-2 (pbk. : alk. paper) 1. Ajax (Web site development technology) 2. Web site development.
3. JavaScript (Computer program language) 4. Asynchronous transfer mode. I. Title.
TK5105.8885.A52M67 2007
006.7'86—dc22
2007015375

Copyright © 2008 Pearson Education, Inc.

All rights reserved. Printed in the United States of America. This publication is protected by copyright, and permission must be obtained from the publisher prior to any prohibited reproduction, storage in a retrieval system, or transmission in any form or by any means, electronic, mechanical, photocopying, recording, or likewise. For information regarding permissions, write to:

Pearson Education, Inc.
Rights and Contracts Department
501 Boylston Street, Suite 900
Boston, MA 02116
Fax (617) 671 3447

CD software is licensed under the GNU Public License version 2 (GPLv2).

ISBN-13: 978-0-13-235008-2

Text printed in the United States on recycled paper at RR Donnelly in Crawfordsville, Indiana.

First printing, July 2007

Editor-in-Chief
Mark Taub

Acquisitions Editor
Debra Williams Cauley

Development Editor
Songlin Qiu

Managing Editor
Gina Kanouse

Project Editors
Michael Thurston
Betsy Harris

Copy Editor
Bart Reed

Indexer
Erika Millen

Proofreader
Leslie Joseph

Technical Editors
Marsha Flynt
Jim Lieb

Publishing Coordinator
Kim Boedigheimer

Multimedia Developer
Chris Negus
Dan Scherf

Cover Design
Alan Clements

Composition
Jake McFarland

Dedication

To my home-building mentor, David Hill, who patiently guided me through the construction of our home while I attempted to juggle a writing career and far too many sports and hobbies.


pref01.html

Negus Live Linux Series

Your practical, hands-on guides to getting real results with free software

Add the free software and examples from the book's CD to your Windows, Mac OS X, or Linux system to follow along with the projects described in the book. Or boot the CD directly to use a complete, prepackaged set of free software tools to play, display, and modify those projects. Start as a novice, by trying out examples...and finish with professional Ajax-enabled Web content!

Overseeing the series is Christopher Negus, bestselling author of the Red Hat Linux Bible series, Linux Toys series, and the signature book for this series, Live Linux CDs.


pref02.html

Acknowledgments

I'd like to thank Debra Williams Cauley and the good folks at Prentice Hall for making this project a reality, as well as Chris Negus for being excited and supportive from the get-go.

A huge thanks also goes to my good friends Stephen Tallent and Fletcher Moore, who came through mightily in the midnight tech-support department, not to mention passing along lots of good ideas and sharing their time generously.

And lastly, my wife deserves the biggest thanks of all for simply being the coolest person on the planet, at least in one nerd writer's humble opinion.


pref03.html

About the Author

Michael Morrison is a writer, developer, toy inventor, and author of a variety of books covering topics such as Java, Web scripting, game development, and mobile devices. Some of Michael's notable writing projects include JavaScript Bible, 6th Edition (Wiley, 2006), Teach Yourself HTML and CSS in 24 Hours, 7th Edition (Sams Publishing, 2005), Beginning Mobile Phone Game Programming (Sams Publishing, 2004), and Java Unleashed (Sams Publishing, 1997). Michael is the instructor of several Web-based courses, including DigitalThink's Introduction to Java 2 series, JavaBeans for Programmers series, and Win32 Programming series (www.digitalthink.com).

In addition to his primary profession as a writer and technical consultant, Michael is the founder of Stalefish Labs (www.stalefishlabs.com), an entertainment company specializing in games, toys, and interactive media. When not glued to his computer, skateboarding, playing hockey, or watching movies with his wife, Masheed, Michael enjoys hanging out by his koi pond.


ch00.html

Introduction

This whole book idea started as a bet I had with my editor that we couldn't pick two random techie topics and tie them together in a book. Two darts flew through the air and the topics "Ajax" and "live CDs" ended up being the result. This book could've just as easily been about Blu-ray on Rails or iPod design patterns. So it's just dumb luck that you're picking up a book on Ajax and live CDs.

And if you believe that, maybe I can interest you in helping fund this startup company I've been thinking about launching! The truth is, Ajax and live CDs are surprisingly good bedfellows in that live CDs provide the perfect environment for building and testing Ajax applications. The whole idea of a "live CD" is that it includes a complete operating system on a single CD. Along with a complete operating system, you get to include any applications you want, such as a Web server that can serve up Ajax applications.

One thing that is unique about Ajax applications as compared to purely client-side applications developed solely in JavaScript is that they require something to happen on the server. In other words, the very premise of Ajax is communication between a client and a server. This means you not only need a server, but you need a server that you have a bit of control over. At the very least, you need the ability to quickly install and test server-side scripts that will handle the server-side processing for your Ajax applications. Live CDs fit the bill nicely in terms of giving you an unbelievably customizable platform for building, testing, and hosting Ajax applications.

As cool as live CDs can be, I have to be honest and say that this book is 95% about Ajax. The live CD facet of this book is primarily a convenience due to the fact that Ajax applications are more demanding of their environment than pure client applications.

OK, so the book is primarily about Ajax, but what does that really mean? It means that in a relatively few number of pages you learn how to do the following things with Ajax:

  • Dynamically load e-book chapters for a Web-based book reader (Chapter 3)

  • Instantly select and view live stock quotes (Chapter 4)

  • Turn any Web page into a news aggregator that understands RSS news feeds (Chapter 5)

  • Add auto-complete functionality to your Web site (Chapter 6)

  • Validate form data and look up location data in real time (Chapter 7)

  • Create a "Web 2.0" image viewer to modernize the way your pages handle images (Chapter 8)

  • Use informational popup windows to dynamically display small nuggets of content (Chapter 9)

  • Add a live weather condition popup window to any link (Chapter 10)

  • Calculate shipping charges on the fly with a U.S. Postal Service Ajax request (Chapter 11)

  • Incorporate an animated five-star rating system into your Web pages (Chapter 12)

These are the kinds of dynamic applications that Ajax makes possible. More importantly, this book uses a construction kit approach to guiding you through adding these features to Ajax applications. Although you will ultimately learn a lot about Ajax as you explore the many examples presented throughout this book, the focus of the book is not on teaching you Ajax. The focus is on showing you how to do cool things with Ajax. Sometimes this requires you to learn something entirely new; other times it simply requires cutting and pasting code. The point is that this book is about doing things.

In my opinion, doing is learning, so you'll ultimately leave this book with a much more thorough understanding of Ajax than when you started. But more importantly, you'll leave it with your own set of Ajax building blocks that you can take with you and apply to your own projects.

The Audience for This Book

I won't lie to you—this book by its very nature has to delve into JavaScript and PHP on a regular basis as the various Ajax examples are presented. However, the original goal of the book was for it to be approachable by anyone with knowledge of HTML and CSS (Cascading Style Sheets), and not necessarily a background in scripting, either client (JavaScript) or server (PHP). I'm not entirely sure that was a realistic goal, but it served me well in trying extremely hard to present enough Ajax coverage for the examples to make sense but not so much to scare away scripting newcomers.

All that being said, you absolutely must know a thing or two about HTML to tackle this book. CSS isn't quite as critical, but it does come up from time to time, so you might as well consider a basic knowledge of CSS a prerequisite. From there, it would serve you well to know something about JavaScript because it is the basis of Ajax. However, I believe you can duck and weave your way through the JavaScript code in this book with a limited knowledge of Web scripting, and still leave with a toolbox full of Ajax goodies that can be readily reused. The PHP code that pops up throughout the book is very simple, and I explain exactly what's going on, so you can definitely get by without knowing anything about PHP.


ch00lev1sec1.html

Introduction

This whole book idea started as a bet I had with my editor that we couldn't pick two random techie topics and tie them together in a book. Two darts flew through the air and the topics "Ajax" and "live CDs" ended up being the result. This book could've just as easily been about Blu-ray on Rails or iPod design patterns. So it's just dumb luck that you're picking up a book on Ajax and live CDs.

And if you believe that, maybe I can interest you in helping fund this startup company I've been thinking about launching! The truth is, Ajax and live CDs are surprisingly good bedfellows in that live CDs provide the perfect environment for building and testing Ajax applications. The whole idea of a "live CD" is that it includes a complete operating system on a single CD. Along with a complete operating system, you get to include any applications you want, such as a Web server that can serve up Ajax applications.

One thing that is unique about Ajax applications as compared to purely client-side applications developed solely in JavaScript is that they require something to happen on the server. In other words, the very premise of Ajax is communication between a client and a server. This means you not only need a server, but you need a server that you have a bit of control over. At the very least, you need the ability to quickly install and test server-side scripts that will handle the server-side processing for your Ajax applications. Live CDs fit the bill nicely in terms of giving you an unbelievably customizable platform for building, testing, and hosting Ajax applications.

As cool as live CDs can be, I have to be honest and say that this book is 95% about Ajax. The live CD facet of this book is primarily a convenience due to the fact that Ajax applications are more demanding of their environment than pure client applications.

OK, so the book is primarily about Ajax, but what does that really mean? It means that in a relatively few number of pages you learn how to do the following things with Ajax:

  • Dynamically load e-book chapters for a Web-based book reader (Chapter 3)

  • Instantly select and view live stock quotes (Chapter 4)

  • Turn any Web page into a news aggregator that understands RSS news feeds (Chapter 5)

  • Add auto-complete functionality to your Web site (Chapter 6)

  • Validate form data and look up location data in real time (Chapter 7)

  • Create a "Web 2.0" image viewer to modernize the way your pages handle images (Chapter 8)

  • Use informational popup windows to dynamically display small nuggets of content (Chapter 9)

  • Add a live weather condition popup window to any link (Chapter 10)

  • Calculate shipping charges on the fly with a U.S. Postal Service Ajax request (Chapter 11)

  • Incorporate an animated five-star rating system into your Web pages (Chapter 12)

These are the kinds of dynamic applications that Ajax makes possible. More importantly, this book uses a construction kit approach to guiding you through adding these features to Ajax applications. Although you will ultimately learn a lot about Ajax as you explore the many examples presented throughout this book, the focus of the book is not on teaching you Ajax. The focus is on showing you how to do cool things with Ajax. Sometimes this requires you to learn something entirely new; other times it simply requires cutting and pasting code. The point is that this book is about doing things.

In my opinion, doing is learning, so you'll ultimately leave this book with a much more thorough understanding of Ajax than when you started. But more importantly, you'll leave it with your own set of Ajax building blocks that you can take with you and apply to your own projects.

The Audience for This Book

I won't lie to you—this book by its very nature has to delve into JavaScript and PHP on a regular basis as the various Ajax examples are presented. However, the original goal of the book was for it to be approachable by anyone with knowledge of HTML and CSS (Cascading Style Sheets), and not necessarily a background in scripting, either client (JavaScript) or server (PHP). I'm not entirely sure that was a realistic goal, but it served me well in trying extremely hard to present enough Ajax coverage for the examples to make sense but not so much to scare away scripting newcomers.

All that being said, you absolutely must know a thing or two about HTML to tackle this book. CSS isn't quite as critical, but it does come up from time to time, so you might as well consider a basic knowledge of CSS a prerequisite. From there, it would serve you well to know something about JavaScript because it is the basis of Ajax. However, I believe you can duck and weave your way through the JavaScript code in this book with a limited knowledge of Web scripting, and still leave with a toolbox full of Ajax goodies that can be readily reused. The PHP code that pops up throughout the book is very simple, and I explain exactly what's going on, so you can definitely get by without knowing anything about PHP.


ch00lev1sec2.html

The Organization of This Book

Although this book follows the charter of the Negus Live Linux Series to provide hands-on experience quickly, the organization of the book is slightly unconventional. The book is divided into three parts:

  • Part I, "Ajax Boot Camp"— This part of the book wastes no time laying just enough groundwork so that you aren't overwhelmed by the intensity of the sample Ajax applications to come. You explore several commercial real-world Ajax applications and get acquainted with the Ajax Toolkit that ships on the accompanying CD-ROM. You'll leave this part of the book revved up to see Ajax in action.

  • Part II, "Building Real-World Ajax Applications"— This part of the book, which constitutes the remainder of the book, is focused entirely on using Ajax to solve real-world problems. From dynamically resolving a ZIP code into a city/state for a data entry form, to injecting an interactive five-star rating system into a page, this part of the book wastes no time and takes no prisoners. Don't get me wrong, it's still a fun read, but don't expect a bunch of tutorial talk or an essay on the history of Ajax. This part of the book in particular is all about doing!

  • Part III, "Appendices"— This part provides additional information you may find helpful. Appendix A, "The Past, Present, and Future of Ajax," paints a picture of where Ajax came from and where it's headed. This is in no way critical to understanding how to add Ajax-powered features to your Web pages, but it does add some perspective to the buzz swirling around Ajax these days. Appendix B, "A Quick and Dirty XMLHttpRequest Reference" is exactly that—a reference for the JavaScript object that serves as the core of Ajax. This object is actually hidden for the most part throughout the book thanks to the Ajax Toolkit, but if you ever want to dig deeper into my code and modify the Toolkit itself, you'll need to get to know the XMLHttpRequest object.

    Finally, Appendix C, "Using the Live Linux CD," is arguably the handiest of all the appendixes because it explains exactly how to use the live Linux CD that comes with the book. Don't worry a bit if you've never used or even heard of a live CD, and don't think you need to be a Linux expert or even have Linux installed. Appendix C addresses the role of the live CD and guides you through how to use it for your particular hardware setup.


ch00lev1sec3.html

About the CD-ROM for This Book

The CD-ROM that comes with this book is where live CDs enter into the Ajax picture. The CD includes a bootable Ubuntu (Linux variant) operating system that includes the Apache Web server and all of the sample Ajax applications covered in the book. Perhaps more interesting is the fact that you can run the applications directly from the CD once it boots up, which is pretty powerful considering that you would otherwise be required to have your own Web server up and running.

There are actually a variety of different ways that you can access and use the Ajax sample applications on the live Linux CD. You don't need to have Linux running on your computer—all you need is a computer with a Pentium III or better processor. The live CD can be run from Windows, Mac OS X, or another Linux variant. To find out more details about how to use the CD to explore the example applications, check out Appendix C, "Using the Live Linux CD."


ch00lev1sec4.html

What You Need to Use This Book

Live Linux CDs are available to run on a range of computer hardware, such as standard PC architecture (i386), PowerPC (PPC), and 64-bit AMD (AMD64). I recommend a minimum of a Pentium III-class PC and at least 128MB of RAM for running the CD that comes with the book. As for hard-disk requirements, you don't even need to have a hard disk in the computer to run the live CD. You might consider getting a USB flash drive (also sometimes called a pen drive, thumb drive, or memory stick). Because live CDs are typically run from read-only media, USB flash drives are good to keep handy in the event that an application needs to write data, as is the case in Chapter 12, "Adding an Ajax-Powered Rating System to Your Site." And again, please refer to Appendix C for detailed instructions on how to use the live CD.


part01.html

Part I: Ajax Boot Camp

Chapter 1 Ajax and a Brave New World Wide Web

Chapter 2 Inside an Ajax Application

Chapter 1. Ajax and a Brave New World Wide Web

Ajax in Cartoons

Ajax Corporation is a fictional corporation used by Metro-Goldwyn-Mayer (MGM) as a parody of Warner Brothers' Acme Corporation, which is featured prominently in Road Runner cartoons. The Ajax Corporation is primarily referenced in Tom and Jerry cartoons.

So I'm waiting for my order at a fast food restaurant the other day, and I started to question why the word "fast" had any business in the description of this particular place. I was eager to have a seat and flip through a magazine, not loiter in a crowded lobby waiting for my "fast" food. This situation got me thinking about Ajax and how it improves the overall Web experience. Yes, in an arguably twisted way, it's possible to look at Ajax through the greasy lens of a hamburger wrapper. And in just a moment you'll see how.

Although it isn't strictly considered an acronym, the name Ajax ultimately derives from Asynchronous JavaScript and XML. The key benefits to Ajax are that it allows you to receive small chunks of data over a Web connection asynchronously, meaning you don't have to wait around for it, and in most cases you can avoid a full Web page reload. The real trick to using Ajax effectively is to get your brain wrapped around what it can do, which is far more important than what it is or why people seem so enamored by it. Ajax is one of those truly rare Web innovations whose benefits are immediately understood once you see it used in the proper context. And sort of like the popular 3M commercials you sometimes see on television, you don't use Ajax to make things, you use it to make things better. This chapter starts you off with a healthy dose of Ajax realism, with a clear focus on what types of problems it aims to solve and why that matters to you. Yes, I also get around to explaining what it is and why people are enamored by it, but that's just icing on the cake.

Dining with Ajax

Getting back to the fast food analogy in the opener, the scenario is a crowded fast food restaurant where you have to stand around waiting for your food before you can sit down and get comfortable. Contrast this fast food dining experience with a full-service restaurant where your meal is delivered to your table after you've already sat down and ordered. There is a considerable luxury in being seated at a table going about your business while someone is busy working away in the kitchen preparing the meal. In the fast food alternative, you must stand around waiting for your food before you can take a seat and get comfortable, assuming you consider fast food seating comforting. The point I'm getting at is that with the fast food approach, the time it takes to prepare your food is time out of your pocket because your dining experience is on hold until the food is ready. With a sit-down dinner, you're able to enjoy a drink, munch on an appetizer, and read a magazine, or talk it up with your dining companion while you wait. These are very different experiences, as illustrated in Figure 1.1.

Figure 1.1. The time it takes to prepare food goes relatively unnoticed in a full-service dinner because you are free to enjoy the dining experience.

Other than the fact that I love eating, especially eating out, the point of this discussion is that Ajax is a Web development technique that offers to upgrade your Web pages to a sit-down dining experience. Traditional Web applications force you to wait while data is searched or otherwise processed on the server. Not so with Ajax. An Ajax Web application goes off and performs its data processing in the background, leaving you to continue to interact with the Web page in the meantime. This may seem like a subtle distinction, but it is not. Just ask yourself, would you rather stand in line at a not-so-fast-food restaurant or relax at a cozy table in a sit-down restaurant?

Note

One small problem with my restaurant analogy for Ajax is that it implies that Ajax Web applications are somehow slower than traditional Web applications. This is not the case. Ajax applications are no faster or slower in terms of raw data processing. In fact, they often give the impression of being faster because processing is typically going on in the background when you don't even realize it.


ch01.html

Part I: Ajax Boot Camp

Chapter 1 Ajax and a Brave New World Wide Web

Chapter 2 Inside an Ajax Application

Chapter 1. Ajax and a Brave New World Wide Web

Ajax in Cartoons

Ajax Corporation is a fictional corporation used by Metro-Goldwyn-Mayer (MGM) as a parody of Warner Brothers' Acme Corporation, which is featured prominently in Road Runner cartoons. The Ajax Corporation is primarily referenced in Tom and Jerry cartoons.

So I'm waiting for my order at a fast food restaurant the other day, and I started to question why the word "fast" had any business in the description of this particular place. I was eager to have a seat and flip through a magazine, not loiter in a crowded lobby waiting for my "fast" food. This situation got me thinking about Ajax and how it improves the overall Web experience. Yes, in an arguably twisted way, it's possible to look at Ajax through the greasy lens of a hamburger wrapper. And in just a moment you'll see how.

Although it isn't strictly considered an acronym, the name Ajax ultimately derives from Asynchronous JavaScript and XML. The key benefits to Ajax are that it allows you to receive small chunks of data over a Web connection asynchronously, meaning you don't have to wait around for it, and in most cases you can avoid a full Web page reload. The real trick to using Ajax effectively is to get your brain wrapped around what it can do, which is far more important than what it is or why people seem so enamored by it. Ajax is one of those truly rare Web innovations whose benefits are immediately understood once you see it used in the proper context. And sort of like the popular 3M commercials you sometimes see on television, you don't use Ajax to make things, you use it to make things better. This chapter starts you off with a healthy dose of Ajax realism, with a clear focus on what types of problems it aims to solve and why that matters to you. Yes, I also get around to explaining what it is and why people are enamored by it, but that's just icing on the cake.

Dining with Ajax

Getting back to the fast food analogy in the opener, the scenario is a crowded fast food restaurant where you have to stand around waiting for your food before you can sit down and get comfortable. Contrast this fast food dining experience with a full-service restaurant where your meal is delivered to your table after you've already sat down and ordered. There is a considerable luxury in being seated at a table going about your business while someone is busy working away in the kitchen preparing the meal. In the fast food alternative, you must stand around waiting for your food before you can take a seat and get comfortable, assuming you consider fast food seating comforting. The point I'm getting at is that with the fast food approach, the time it takes to prepare your food is time out of your pocket because your dining experience is on hold until the food is ready. With a sit-down dinner, you're able to enjoy a drink, munch on an appetizer, and read a magazine, or talk it up with your dining companion while you wait. These are very different experiences, as illustrated in Figure 1.1.

Figure 1.1. The time it takes to prepare food goes relatively unnoticed in a full-service dinner because you are free to enjoy the dining experience.

Other than the fact that I love eating, especially eating out, the point of this discussion is that Ajax is a Web development technique that offers to upgrade your Web pages to a sit-down dining experience. Traditional Web applications force you to wait while data is searched or otherwise processed on the server. Not so with Ajax. An Ajax Web application goes off and performs its data processing in the background, leaving you to continue to interact with the Web page in the meantime. This may seem like a subtle distinction, but it is not. Just ask yourself, would you rather stand in line at a not-so-fast-food restaurant or relax at a cozy table in a sit-down restaurant?

Note

One small problem with my restaurant analogy for Ajax is that it implies that Ajax Web applications are somehow slower than traditional Web applications. This is not the case. Ajax applications are no faster or slower in terms of raw data processing. In fact, they often give the impression of being faster because processing is typically going on in the background when you don't even realize it.


ch01lev1sec1.html

Part I: Ajax Boot Camp

Chapter 1 Ajax and a Brave New World Wide Web

Chapter 2 Inside an Ajax Application

Chapter 1. Ajax and a Brave New World Wide Web

Ajax in Cartoons

Ajax Corporation is a fictional corporation used by Metro-Goldwyn-Mayer (MGM) as a parody of Warner Brothers' Acme Corporation, which is featured prominently in Road Runner cartoons. The Ajax Corporation is primarily referenced in Tom and Jerry cartoons.

So I'm waiting for my order at a fast food restaurant the other day, and I started to question why the word "fast" had any business in the description of this particular place. I was eager to have a seat and flip through a magazine, not loiter in a crowded lobby waiting for my "fast" food. This situation got me thinking about Ajax and how it improves the overall Web experience. Yes, in an arguably twisted way, it's possible to look at Ajax through the greasy lens of a hamburger wrapper. And in just a moment you'll see how.

Although it isn't strictly considered an acronym, the name Ajax ultimately derives from Asynchronous JavaScript and XML. The key benefits to Ajax are that it allows you to receive small chunks of data over a Web connection asynchronously, meaning you don't have to wait around for it, and in most cases you can avoid a full Web page reload. The real trick to using Ajax effectively is to get your brain wrapped around what it can do, which is far more important than what it is or why people seem so enamored by it. Ajax is one of those truly rare Web innovations whose benefits are immediately understood once you see it used in the proper context. And sort of like the popular 3M commercials you sometimes see on television, you don't use Ajax to make things, you use it to make things better. This chapter starts you off with a healthy dose of Ajax realism, with a clear focus on what types of problems it aims to solve and why that matters to you. Yes, I also get around to explaining what it is and why people are enamored by it, but that's just icing on the cake.

Dining with Ajax

Getting back to the fast food analogy in the opener, the scenario is a crowded fast food restaurant where you have to stand around waiting for your food before you can sit down and get comfortable. Contrast this fast food dining experience with a full-service restaurant where your meal is delivered to your table after you've already sat down and ordered. There is a considerable luxury in being seated at a table going about your business while someone is busy working away in the kitchen preparing the meal. In the fast food alternative, you must stand around waiting for your food before you can take a seat and get comfortable, assuming you consider fast food seating comforting. The point I'm getting at is that with the fast food approach, the time it takes to prepare your food is time out of your pocket because your dining experience is on hold until the food is ready. With a sit-down dinner, you're able to enjoy a drink, munch on an appetizer, and read a magazine, or talk it up with your dining companion while you wait. These are very different experiences, as illustrated in Figure 1.1.

Figure 1.1. The time it takes to prepare food goes relatively unnoticed in a full-service dinner because you are free to enjoy the dining experience.

Other than the fact that I love eating, especially eating out, the point of this discussion is that Ajax is a Web development technique that offers to upgrade your Web pages to a sit-down dining experience. Traditional Web applications force you to wait while data is searched or otherwise processed on the server. Not so with Ajax. An Ajax Web application goes off and performs its data processing in the background, leaving you to continue to interact with the Web page in the meantime. This may seem like a subtle distinction, but it is not. Just ask yourself, would you rather stand in line at a not-so-fast-food restaurant or relax at a cozy table in a sit-down restaurant?

Note

One small problem with my restaurant analogy for Ajax is that it implies that Ajax Web applications are somehow slower than traditional Web applications. This is not the case. Ajax applications are no faster or slower in terms of raw data processing. In fact, they often give the impression of being faster because processing is typically going on in the background when you don't even realize it.


ch01lev1sec2.html

Ajax, Sting, and Asynchronicity

In 1983 the Police released the album Synchronicity, and it went on to sell millions of copies and launch major hits such as "Every Breath You Take." I bet Sting never realized that a few decades later his album title would be the antagonist in numerous tech books and articles. As it turns out, synchronicity is the bane of Web user interfaces, as it implies that one thing must finish before another can start. In a synchronous Web page, you cannot start Task B until Task A has completely finished, even if Task A takes a while. For example, a synchronous online music service wouldn't allow you to continue browsing for music while it's busy serving up a song for download.

Note

One reason Sting has probably never made the connection between the album Synchronicity and the tech world is because the album actually refers to a psychological principle developed by Swiss psychologist Carl Jung. In this context, Synchronicity refers to a "meaningful coincidence," as in when two seemingly unrelated things take place that have more of a connection than mere coincidence. I apologize if I'm better at explaining techie computer topics than I am psychology principles.

Another example more to the point with Ajax is the shipping cost in an online shopping cart, which is often a critical part of a shopping transaction and in some cases can determine whether an item is worth purchasing. Take this from someone who has bought an automobile online—shipping charges can make or break an online purchase. The problem is that many shopping carts are designed to get all of your information, in many cases including your credit card number, before calculating and revealing the shipping charge. I don't know about you, but if I haven't yet committed to a purchase, there's no way I'm going to enter my credit card number.

Even for shopping carts that are designed to calculate shipping early in the checkout process, you still have the issue of a server request/response, which can take time and will ultimately result in a page reload in order to reveal the shipping charge on the page. While this server request is taking place, the order-entry user interface is effectively frozen, which is not a good thing. It would make so much more sense if the shipping charge was seamlessly calculated and displayed as you enter the shipping address. Since the item being purchased is already in the cart, all the shopping cart application needs is a ZIP code to fire off a server request and get busy calculating the charges. This action can take place in the background while you're filling out the rest of the order information. Similarly to the dining example, the wait involved in calculating the shipping charge is all but eliminated because you're allowed to do something else useful while it is happening.


ch01lev1sec3.html

To Reload, or Not Reload

As I alluded to already, a frozen user interface is only part of the problem with traditional Web applications. The other side of the equation is the fact that a page must be reloaded for every server response. More specifically, when the server sends the shipping charge back from the server, the page must be reloaded to reflect the change because the server is responding with an entire Web page. Every change to a page that is based upon a server response requires a page refresh. This is a terribly annoying problem not only because page reloads/refreshes take time, but also because the page effectively flickers and blinks with each change.

Note

There is wide debate over the notion of applying version numbers to the Web as a whole. It's very difficult to pigeonhole such a divergent beast into a numbering system, no more than you would label a highway system Autobahn 3.0. However, the general idea that there are discrete, evolutionary steps in the design of Web applications is absolutely valid. So maybe the highway analogy isn't so far off after all—think of traditional Web applications as dirt roads, whereas Ajax-powered Web applications are asphalt interstate highways.

There is also a significant efficiency issue in that the entire contents of the page have to be resent with each page reload, even if only a tiny piece of data (a shipping charge, for example) is being updated. This is a waste of bandwidth and a waste of the user's time. This type of Web application is what has generally become known as a Web 1.0 application. Ajax is playing a major role in ushering in a new generation of applications that fall under the Web 2.0 moniker, which "feel" more like true desktop applications.

Ajax solves the page-reload problem by reducing server requests and responses to only the exact data you need, as opposed to an entire page. In the case of the shipping charge request, the server just sends back a dollar amount, in which case the page updates only the shipping charge area of the page with server data, and then calculates a new total for the purchase. The entire page is not resent, no reload is necessary, and no flicker occurs. Figure 1.2 illustrates how Ajax improves the shipping charge calculation process.

Figure 1.2. Ajax makes it possible to calculate a shipping charge without interrupting the user experience.

[View full size image]


ch01lev1sec4.html

What Exactly Is Ajax?

I've resisted the urge thus far to get overly specific about what Ajax is because it is much more important for you to understand what it does. To say that Ajax is a programming technique that involves the combination of JavaScript and XML is pointless if you don't understand the kinds of problems it solves. Hopefully enough groundwork has been laid that you now have a basic grasp of the problems Ajax addresses.

So then, what is Ajax? Ajax is a specific Web development approach that involves the usage of JavaScript and quite often XML. That's it. It's not a fancy browser plug-in or hip new programming language. It's just a programming technique involving technologies that have already been around a while.

The real muscle behind Ajax is a single JavaScript object that makes it possible to communicate with a Web server asynchronously. In traditional Web applications, the browser itself typically presents the only means of communicating with a server, and more importantly, it does so a Web page at a time. Ajax introduces the notion of using JavaScript to communicate with a server. Behind the scenes it's still the browser doing the work, but the net effect is that your JavaScript code is able to carry on a conversation with a Web server to send and receive discrete pieces of data. And this communication takes place asynchronously, which means it occurs in the background without interrupting anything else.

For now, it's not terribly important for you to know any of the specifics regarding the JavaScript object that makes Ajax possible. The next chapter gets into more detail concerning the nuts and bolts of Ajax and how to assemble Ajax code.

Note

Keep in mind that the whole point of this book is to provide you with a plug-and-play Ajax framework that minimizes code development. You'll be able to reuse the code in this book with a minimal knowledge of the Ajax code and how it works. Not only that, but you can use the enclosed live Linux CD to experiment with many of the examples directly from your PC.


ch01lev1sec5.html

Real-World Ajax

This book is inherently noninteractive, and I can prove it. Click here with your finger and you'll see what I mean. See, no new page appeared. Knowing that the printed page is rather static, I encourage you to take a few moments to tinker with some real Ajax applications online to get a feel for how they compare with traditional Web applications. The next few sections present some of the more popular and compelling Ajax applications, and help direct you toward their specific features that benefit the most from Ajax:

  • Google Suggest

  • Netflix

  • Flickr

  • Google Maps

Since you probably already use some of these Web applications, it will be even more insightful as you find out how Ajax makes specific features possible. After this little real-world tour, you'll revisit the shipping charge calculator example in the context of a real Ajax application that is provided on the enclosed live Linux CD.

Google Suggest

Google Suggest (http://labs.google.com/suggest/) is a great example of a relatively simple Ajax application that is sneakily powerful. It turns out that "sneakily powerful" is something you may be thinking to yourself a lot as you explore Ajax and its many possibilities. Google Suggest is the regular Google search engine but with a suggestive text-entry feature that attempts to help you narrow down your search based upon actual Google search data.

As you type in a search phrase in Google Suggest, a dropdown list immediately appears with possible matches for the phrase. To accept one of the suggested phrases, just click it with your mouse, or cursor down and select it. What makes this Ajax application so cool is how each possible match has the number of matches listed out to the side of it. In other words, you are provided with an immediate clue as to the popularity of a particular search phrase.

As you experiment with Google Suggest, the key thing to note from a development perspective is how it is seamlessly making a round-trip to the server with each character you enter. That's pretty amazing when you think about it. Talk about a responsive user interface! This is exactly the kind of "feel" that Ajax is intended to impart on modern Web applications. Chapter 6, "Reading the User's Mind with Auto-Complete," revisits Google Suggest as it shows you how to employ your own "auto-complete" feature using Ajax. But don't wait until Chapter 6, go ahead and try out Google Suggest right now.

Netflix

Chances are you've already been basking in the comfortable glow of Ajax without even knowing it. If you use Netflix (http://www.netflix.com/) for movie rentals, then you're already somewhat of an Ajax veteran, at least from the user side of things. Netflix uses Ajax to carry out a popular trick where a popup window automatically appears when you hover over a piece of information (a movie icon in this case) with the mouse pointer.

If you simply hover over the small icon of a movie, a popup window appears with a complete movie description and related movie information. All this movie data is retrieved from the server via Ajax in the background as the hover begins. From the user's perspective, this is all gravy because you don't even realize a server communication is taking place until it is over (the popup window appears). Again, Ajax adds a significant usability feature in an entirely seamless manner.

One interesting thing to note about using Ajax for popup windows is how the Netflix popup disappears automatically once you move the mouse pointer off of the movie in question. This helps to improve the perception that the popup is purely informative and not an annoying advertising popup that you have to click to get rid of—in the case of Netflix, the popups truly are a welcome addition to the user interface. You can experience Ajax on Netflix even if you don't have a Netflix account—just go to http://www.netflix.com/ and click Browse Selection to find some movies to hover around. Incidentally, you learn how to inject informational popup windows into your own pages in Chapter 9, "Presenting Information with Slick Popups."

Note

For another interesting usage of Ajax for displaying popup windows, check out the Invisible Ad advertisement service at http://www.theinvisiblead.com/. It is a very unconventional advertising concept involving a huge grid of tiny squares that you must hover over with your mouse in order to view ads. This type of advertising is known as pixel ads because you literally pay for each pixel of ad space on the screen. Groundbreaking? Silly? You be the judge!

Flickr

Without a doubt my favorite commercial Ajax application thus far, Flickr (http://www.flickr.com/) is Ajax-powered to the max. If you aren't familiar with it, Flickr is an online photo-sharing community. What makes Flickr so unusual is how thoroughly it uses Ajax to give it the feel of a desktop application. There are very few tasks within Flickr that require a page reload or that make you sit around twiddling your thumbs during a server request/response. Figure 1.3 shows how intuitive the editing of a photo caption is in Flickr thanks to a heavy dose of Ajax.

Figure 1.3. Editing a Flickr photo caption occurs "in place" and without any page refreshes, even when saving the modified caption.

[View full size image]

The figure shows a picture in my photo collection with its caption being edited. It's important to understand that the edit field and its associated Save and Cancel buttons appeared automatically when I clicked the photo's caption. After changing the caption, you simply click the Save button and the changes are committed to the server immediately. No waiting around for a new page to open, no confirmation dialog box, nothing. The caption just changes from edit mode back to a static piece of text. Like I said earlier, "sneakily powerful" comes to mind when you think about how cleanly the caption-editing task is made thanks to Ajax.

Flickr doesn't stop with photo caption editing when it comes to its use of Ajax. There are all kinds of clever ways that Ajax permeates the Flickr user interface. I could spend a few more pages spoon-feeding them to you, or I could just turn you loose to try them out on your own. You'll need to create a free Flickr account to truly experience the user interface, but that only takes a few simple steps. You can start out at http://www.flickr.com/.

Google Maps

I have to admit that it pained me a little to crown Flickr my favorite commercial Ajax application because there is another that is dear to my heart. I'm talking about Google Maps (http://maps.google.com/), which in many ways is the godfather of Ajax applications. It was only a few short years ago that Web developers across the globe were scratching their heads over how Google Maps could possibly be doing what it was doing, and with such speed. As it turns out, the trick up the sleeve of Google Maps was and still is Ajax. In my mind, Google Maps is still the ultimate example of processing data in the background to improve the user experience.

The primary trick employed by Google Maps is constantly anticipating and loading map data before it is needed. In other words, Google Maps isn't concerned so much about what part of the map you are currently viewing as it is what part of the map you're going to be viewing next. Safe guesses include the areas around the currently viewed area, as well as zoomed-in and zoomed-out versions of the current area. It turns out that Google Maps generally outworks the user by loading data faster than the user is able to process it. So by the time you get around to exploring a different part of the map, Google Maps is already ahead of you and has preloaded the map data. The net effect is a shockingly responsive user interface that would be impossible without the assistance of Ajax in loading map data in the background.

Ajax also enters the picture with Google Maps when it comes to customizing a map with your own information. Google publishes a special API (Application Programming Interface) for interacting with Google Maps, and it is based entirely upon Ajax. For example, you can create your own custom markers (push pins) to place on map locations and even tie them to custom popup windows that display additional information about the locations.


ch01lev1sec6.html

Ajax Isn't for Everything

I'm guessing the little tour of real-world Ajax applications has gotten you excited about injecting a little Ajax into your own Web pages. That's a very good thing. However, I must caution you that Ajax is not a one-size-fits-all solution. Like most things in life, a little moderation can go a long way toward getting the most benefit out of Ajax.

Earlier in the chapter you found out about the main problems that Ajax solves. Working back from these problems, it's possible to come up with a list of scenarios where Ajax makes a lot of sense. By analyzing this scenario list, it's also possible to determine when Ajax isn't an ideal solution. Use this list as a basis for trying to determine whether Ajax truly stands to help your Web pages. Understand that the list isn't all encompassing, but is intended more as a general guide for assessing the practical usefulness of Ajax. Here goes:

  • First and foremost, Ajax always involves server communication, or more specifically, data flowing from the server to the client Web browser. If your Web page does not hit a Web server for data of some sort, there's no point in using Ajax. You can certainly still use JavaScript to make the page more interactive, but Ajax isn't strictly necessary.

  • One of the key points of Ajax is to update a page without requiring a refresh/reload. If your application inherently requires a new page to be opened, such as a link to a new page in a series of discrete pages, then Ajax is probably not the answer. On the other hand, maybe you can merge several pages into a single Ajax-powered page that doesn't need reloading.

    Note

    Some people mistakenly refer to any highly responsive Web user interface as an "Ajax user interface." Strictly speaking, such an interface must involve server communication in order to qualify as an Ajax solution, at least in my humble opinion. That's not to say that responsive user interfaces aren't closely tied to Ajax, because they certainly are. But the fact remains that Ajax is about getting data from a server asynchronously. I'm not trying to split hairs semantically in regard to what is and isn't Ajax; I'm just trying to help you know when it makes sense to use Ajax.

  • Another key point of Ajax is asynchronous communications, which is how Ajax shuttles data in the background so that other stuff can take place in the foreground. If your application specifically needs one thing to happen before another, then Ajax probably isn't a good idea. Maybe a certain block of user entry data must be validated before going any further, in which case you probably really do want to open a new page or make the user wait while the data is verified. In either case, Ajax doesn't really help.

The point I'm making here is that Ajax is incredibly powerful when used properly, but knowing when to use it is important. The three preceding points should serve as guides for assessing whether or not it makes sense to inject Ajax into your application. Additionally, the examples you explore throughout the remainder of the book will shed additional light on when and how Ajax should find its way into your Web pages.


ch01lev1sec7.html

The Shipping Charge Calculator Revisited

Earlier in the chapter I made a big deal about how annoying it is in an online shopping cart to find out the shipping charge only by first divulging financial information or stepping through a sequence of Web pages. I made a case for how Ajax could dramatically improve the situation by obtaining the shipping charge from a server in the background once you enter the ZIP code for where the order is being sent. You would then be free to continue entering order information instead of waiting for the server or being interrupted with a page reload. Figure 1.4 shows what such a shopping cart might look like prior to entering the ZIP code for shipping.

Figure 1.4. Part of the check-out process for any online shopping cart involves gathering the shipping information and displaying a total.

[View full size image]

In this example, the check-out process has already progressed to the point of the purchase item being selected; all that remains is getting the shipping information, calculating a total, and completing the payment. This particular example stops short of completing the payment, instead focusing on streamlining the retrieval of the shipping charge and calculating a check-out total based on those charges.

With Ajax now in the mix, it becomes possible to get the shipping charge directly from a shipping provider's server (in this case the U.S. Postal Service) as soon as the ZIP code is entered. Figure 1.5 shows the order entry page with the ZIP code partially entered. Notice at this point that the shipping charge has yet to be retrieved because I'm still entering the ZIP code.

Figure 1.5. Nothing happens while the ZIP code is being entered because you need the entire ZIP code to request the shipping charge.

[View full size image]

Note

The USPS Web Tools API, which is responsible for allowing you to retrieve a shipping charge via Ajax, also supports the verification of shipping information. For example, you could take order entry to another level entirely by using the USPS server to find out the city and state from a ZIP code, thereby eliminating two pieces of user-entered information. You learn more about the USPS Web Tools API in Chapter 11, "Building an Ajax Shipping Calculator," when we dissect the shipping rate calculator example in a bit more detail within the context of a real Ajax application.

Once the ZIP code is completely entered and I move to the next field in the user interface (Phone Number), the shipping charge magically appears and the check-out total is calculated (see Figure 1.6). This shipping charge was obtained behind-the-scenes directly from a U.S. Postal Service server and then reflected on the page without any noticeable delay or page interruption.

Figure 1.6. The shipping charge is retrieved and the check-out total is calculated in the background without distraction.

[View full size image]

Even if the USPS server had taken its sweet time returning the shipping charge, the user experience wouldn't have suffered much because the user is free to continue entering information. Additionally, any changes to the ZIP code result in a new server request and a new shipping charge. Not only that, but the specific USPS shipping service (Parcel Post, Priority Mail, etc.) can be changed, which also results in a new shipping charge being retrieved.

That last little trick in this Ajax example is revealed when you enter a ZIP code that isn't supported. Maybe the specific item can't be shipped to a certain region—or maybe, as in this example, you limit the ZIP code for testing purposes. Regardless of the motivation, if the ZIP code doesn't result in a valid shipping charge, an error notice is displayed next to the ZIP code field, as shown in Figure 1.7.

Figure 1.7. An error message appears next to the ZIP code field if you enter a ZIP code that isn't accepted.

[View full size image]

Chapter 11 explores the inner workings of this example in more detail. For now, just know that the example is limited to only working for the ZIP code 20008, meaning that any other ZIP codes will result in an error. This limitation has to do with using the USPS Web Tools API in "test mode," not the example code itself.


ch01lev1sec8.html

Summary

The last thing I wanted to do in this chapter was give you a long-winded summary of how Ajax came to be and who made it possible. I realize your motivation in buying this book is to do some cool stuff with what is without question one of the coolest programming techniques to hit the Web in quite some time. The goal of this chapter was to get you acclimated with what Ajax can do and why it is relevant to both your current applications and the future of the Web.

Anyone developing applications for the Web should be thinking about how to make their applications better: more interactive, more intuitive, and less like the Web of old. We are standing at the edge of an exciting new Web that has the potential to erase the line between Web app and desktop app. When you think about it, why should that distinction matter anyway? An application is just a way to do something useful or fun with a computer, and Ajax is a tool that can make many online applications dramatically better. The rest of this book shows you exactly how to make your applications better with Ajax.


ch02.html

Chapter 2. Inside an Ajax Application

Ajax on the High Seas

Several ships in the United States Navy have taken the name Ajax over the years, with the first USS Ajax launched in 1864. The most recent USS Ajax was a repair ship that saw duty in both World War II and the Vietnam War, and was ultimately decommissioned in 1986.

If it's one thing I hate, it's computer books that spend the first five chapters laying the groundwork for everything to come. Too many books feel like they have to teach you a little bit about everything instead of focusing on the one topic at hand. For this reason, you start off this chapter with just a bit more setup and then dive right into the guts of Ajax. If you think you need to brush up a bit on HTML and CSS, or maybe you think a quick JavaScript or XML tutorial might be helpful, then by all means take a break and brush up on them. Just don't hold your breath for me to waste your afternoon holding your hand through those topics when we've got Ajax business to take care of.

I'm not trying to scare you away; I'm just trying to get you fired up to jump into the cool stuff that you bought this book to learn how to do. By the end of this chapter, you'll have completed your first fully functioning Ajax application. Not only that, but you'll also have a pretty good sense of how to customize that application to do things it was probably never even intended to do. That's a good thing. Improvise, invent; that's the spirit here. Now let's get started!

The following files are used by the Booker application in this chapter and are located on the live Linux CD-ROM with the book in the chap02 example code folder:

  • booker.html—Main Web page

  • ajaxkit.js—Core Ajax functions for the Ajax Toolkit

  • domkit.js—DOM-related functions for the Ajax Toolkit

  • book_alicewonderland.xml—Alice's Adventures in Wonderland XML e-book

  • book_frankenstein.xml—Frankenstein XML e-book

  • book_mobydick.xml—Moby Dick XML e-book

  • book_warandpeace.xml—War and Peace XML e-book

  • book_warofworlds—War of the Worlds XML e-book

The Nuts and Bolts of Ajax

You probably now have a decent feel for the fact that Ajax isn't so much a single technology as it is a specific application of other technologies. Understanding how these other technologies fit together within the context of an Ajax application is important in understanding how to build and modify your own Ajax applications. So let's explore the component technologies that make Ajax work. Figure 2.1 shows how the major Ajax technologies fit together in a typical Ajax application.

Figure 2.1. HTML, CSS, JavaScript, XML, and a server program such as PHP all work together to coordinate an Ajax request and response.

Notice in the figure that the Ajax request/response process unfolds in an orderly fashion, as is evident by the numbers 1 through 3. Keep this figure in mind as you learn more about how the different Ajax components fit together in the next few sections.

HTML and CSS

It would be difficult to create any Web page without a little HTML since it is the language of the Web. In Ajax applications, HTML still serves as the structural portion of content on the page, such as text, images, form fields, etc. In fact, most of the HTML code in Ajax applications is nothing special—the interesting stuff takes place primarily in JavaScript code, which I get to in a moment.

If you've done any Web page creation in the past few years, you likely already have an appreciation of Cascading Style Sheets (CSS) and how important they are to creating visually attractive Web pages. CSS allows you to cleanly separate the appearance of a Web page from its structure, with the end result being pages that are more easily maintained, not to mention prettier. CSS enters the Ajax picture in that it provides you with a means of applying styles to change the look and feel of HTML content dynamically. For example, you might want to highlight an invalid data entry field upon validating the data against a database through an Ajax request. The highlighting in this example would be carried out on an HTML form element via CSS.

JavaScript

JavaScript's job in Ajax is to orchestrate everything on the client side of the equation, which includes any and all logic that must be carried out by the browser. Don't forget that the very essence of Ajax is an exchange of data between a client (browser) and a server (Web server), so you'll always be thinking in terms of client/server communication when designing and building Ajax applications. JavaScript code runs on the browser, and is used to initiate Ajax requests and handle the resulting data returned by the server.

You use JavaScript to package up user data for sending to the server, as well as receiving the server's response and presenting it back to the user in a meaningful way. Of course, this means that HTML and CSS factor heavily into the JavaScript code for an Ajax application, with JavaScript often utilizing the Document Object Model (DOM) to dynamically alter HTML elements based upon Ajax responses. The dashed lines in Figure 2.1 indicate JavaScript's ability to alter HTML and CSS code dynamically using the DOM.

Note

You aren't expected to understand how to program in JavaScript to be able to reuse the examples in this book in your own Web pages. However, it is impossible to explore Ajax at any depth without digging into JavaScript code, so a cursory understanding of JavaScript is important if you plan on taking any of the sample code to another level.

XML and Ajax Data

OK, so you know that an Ajax Web page is still made up of HTML and CSS, and that it can be dynamically tinkered with using crafty JavaScript code that manages Ajax requests and responses. I still haven't explained the nature of the data that is sent between the client and server in an Ajax request/response sequence. And part of the reason is because the format of data in an Ajax transaction is not set in stone. You have the freedom of using several data formats to suit the specific needs of each application. In other words, you can carefully tailor the representation of data to each Ajax application.

One of the most compelling reasons to use Ajax is to take advantage of the XML data standard, which provides a highly structured means of organizing information. XML is particularly adept at representing complex data that would otherwise be difficult to represent, such as a hierarchical database with several levels of nested data. Ajax fully supports XML on either side of the request/response equation, meaning you can send and/or receive data in XML.

While XML is a very good thing, it is not the magical solution to every Ajax problem. In fact, it is perfectly acceptable, and in many cases desirable, to use raw text data as the format for Ajax data exchange. For example, it is very concise to pass data along to the server as simple name/value pairs like you often see in URLs, as in

fname=Michael&lname=Morrison

Compare this to the same information structured in XML:

<fname>Michael</fname>
<lname>Morrison</lname>

The URL name/value version of the data is much more effective in this case because the data is so simple.

The bottom line is that the format of data shuttling around in an Ajax application is entirely dependent on the specific needs of the application. Throughout the book you'll encounter applications that use several different data types, including raw text, XML, and another type known as JSON (JavaScript Object Notation).

PHP and the Server

One facet of Ajax that is often misunderstood by newcomers is the fact that it is entirely dependent on a server program accepting requests and responding in some way. The server program is the hidden ingredient in the familiar Asynchronous JavaScript + XML recipe that you typically see associated with the term Ajax. On a practical level, this means that you can't just assemble a Web page with some JavaScript code and crank out an Ajax application—there has to be a server-side component that responds to requests from the client.

The role of the server program in an Ajax application is entirely specific to each Ajax application, but in general you will find that most Ajax server programs are responsible for looking up some piece of information and returning it to the client. For example, an Ajax employee directory application might pass an employee ID to the server, in which case the server program looks up the ID in a database and returns the employee's name and contact information. Or, as in the example you pondered in the previous chapter, information about an item to be shipped might be passed to the server, after which the server looks up the shipping rate and returns it.

Unlike on the client side of an Ajax application, which is exclusively the domain of JavaScript, the server side is wide open in terms of what programming language is used to create the server program. Fortunately, there are some popular options that are widely supported and relatively easy to modify and use. One of these options is PHP, which is a very popular server scripting language that is handy in creating Ajax applications. Similar to JavaScript code that is run on a browser, PHP code is run on a server. Referring back to Figure 2.1 once more, you can see how a PHP program on the server receives an Ajax request from the browser (thanks to JavaScript), and then responds after processing the request.

The interesting thing about PHP code, and all server-side scripts for that matter, is that they ultimately end up passing data back to the client. When working with PHP, you have to always keep in mind that whatever you're doing will culminate in data being shuttled back to the browser. In the case of an Ajax application, a PHP script is shuttling data back to an Ajax request.


ch02lev1sec1.html

Chapter 2. Inside an Ajax Application

Ajax on the High Seas

Several ships in the United States Navy have taken the name Ajax over the years, with the first USS Ajax launched in 1864. The most recent USS Ajax was a repair ship that saw duty in both World War II and the Vietnam War, and was ultimately decommissioned in 1986.

If it's one thing I hate, it's computer books that spend the first five chapters laying the groundwork for everything to come. Too many books feel like they have to teach you a little bit about everything instead of focusing on the one topic at hand. For this reason, you start off this chapter with just a bit more setup and then dive right into the guts of Ajax. If you think you need to brush up a bit on HTML and CSS, or maybe you think a quick JavaScript or XML tutorial might be helpful, then by all means take a break and brush up on them. Just don't hold your breath for me to waste your afternoon holding your hand through those topics when we've got Ajax business to take care of.

I'm not trying to scare you away; I'm just trying to get you fired up to jump into the cool stuff that you bought this book to learn how to do. By the end of this chapter, you'll have completed your first fully functioning Ajax application. Not only that, but you'll also have a pretty good sense of how to customize that application to do things it was probably never even intended to do. That's a good thing. Improvise, invent; that's the spirit here. Now let's get started!

The following files are used by the Booker application in this chapter and are located on the live Linux CD-ROM with the book in the chap02 example code folder:

  • booker.html—Main Web page

  • ajaxkit.js—Core Ajax functions for the Ajax Toolkit

  • domkit.js—DOM-related functions for the Ajax Toolkit

  • book_alicewonderland.xml—Alice's Adventures in Wonderland XML e-book

  • book_frankenstein.xml—Frankenstein XML e-book

  • book_mobydick.xml—Moby Dick XML e-book

  • book_warandpeace.xml—War and Peace XML e-book

  • book_warofworlds—War of the Worlds XML e-book

The Nuts and Bolts of Ajax

You probably now have a decent feel for the fact that Ajax isn't so much a single technology as it is a specific application of other technologies. Understanding how these other technologies fit together within the context of an Ajax application is important in understanding how to build and modify your own Ajax applications. So let's explore the component technologies that make Ajax work. Figure 2.1 shows how the major Ajax technologies fit together in a typical Ajax application.

Figure 2.1. HTML, CSS, JavaScript, XML, and a server program such as PHP all work together to coordinate an Ajax request and response.

Notice in the figure that the Ajax request/response process unfolds in an orderly fashion, as is evident by the numbers 1 through 3. Keep this figure in mind as you learn more about how the different Ajax components fit together in the next few sections.

HTML and CSS

It would be difficult to create any Web page without a little HTML since it is the language of the Web. In Ajax applications, HTML still serves as the structural portion of content on the page, such as text, images, form fields, etc. In fact, most of the HTML code in Ajax applications is nothing special—the interesting stuff takes place primarily in JavaScript code, which I get to in a moment.

If you've done any Web page creation in the past few years, you likely already have an appreciation of Cascading Style Sheets (CSS) and how important they are to creating visually attractive Web pages. CSS allows you to cleanly separate the appearance of a Web page from its structure, with the end result being pages that are more easily maintained, not to mention prettier. CSS enters the Ajax picture in that it provides you with a means of applying styles to change the look and feel of HTML content dynamically. For example, you might want to highlight an invalid data entry field upon validating the data against a database through an Ajax request. The highlighting in this example would be carried out on an HTML form element via CSS.

JavaScript

JavaScript's job in Ajax is to orchestrate everything on the client side of the equation, which includes any and all logic that must be carried out by the browser. Don't forget that the very essence of Ajax is an exchange of data between a client (browser) and a server (Web server), so you'll always be thinking in terms of client/server communication when designing and building Ajax applications. JavaScript code runs on the browser, and is used to initiate Ajax requests and handle the resulting data returned by the server.

You use JavaScript to package up user data for sending to the server, as well as receiving the server's response and presenting it back to the user in a meaningful way. Of course, this means that HTML and CSS factor heavily into the JavaScript code for an Ajax application, with JavaScript often utilizing the Document Object Model (DOM) to dynamically alter HTML elements based upon Ajax responses. The dashed lines in Figure 2.1 indicate JavaScript's ability to alter HTML and CSS code dynamically using the DOM.

Note

You aren't expected to understand how to program in JavaScript to be able to reuse the examples in this book in your own Web pages. However, it is impossible to explore Ajax at any depth without digging into JavaScript code, so a cursory understanding of JavaScript is important if you plan on taking any of the sample code to another level.

XML and Ajax Data

OK, so you know that an Ajax Web page is still made up of HTML and CSS, and that it can be dynamically tinkered with using crafty JavaScript code that manages Ajax requests and responses. I still haven't explained the nature of the data that is sent between the client and server in an Ajax request/response sequence. And part of the reason is because the format of data in an Ajax transaction is not set in stone. You have the freedom of using several data formats to suit the specific needs of each application. In other words, you can carefully tailor the representation of data to each Ajax application.

One of the most compelling reasons to use Ajax is to take advantage of the XML data standard, which provides a highly structured means of organizing information. XML is particularly adept at representing complex data that would otherwise be difficult to represent, such as a hierarchical database with several levels of nested data. Ajax fully supports XML on either side of the request/response equation, meaning you can send and/or receive data in XML.

While XML is a very good thing, it is not the magical solution to every Ajax problem. In fact, it is perfectly acceptable, and in many cases desirable, to use raw text data as the format for Ajax data exchange. For example, it is very concise to pass data along to the server as simple name/value pairs like you often see in URLs, as in

fname=Michael&lname=Morrison

Compare this to the same information structured in XML:

<fname>Michael</fname>
<lname>Morrison</lname>

The URL name/value version of the data is much more effective in this case because the data is so simple.

The bottom line is that the format of data shuttling around in an Ajax application is entirely dependent on the specific needs of the application. Throughout the book you'll encounter applications that use several different data types, including raw text, XML, and another type known as JSON (JavaScript Object Notation).

PHP and the Server

One facet of Ajax that is often misunderstood by newcomers is the fact that it is entirely dependent on a server program accepting requests and responding in some way. The server program is the hidden ingredient in the familiar Asynchronous JavaScript + XML recipe that you typically see associated with the term Ajax. On a practical level, this means that you can't just assemble a Web page with some JavaScript code and crank out an Ajax application—there has to be a server-side component that responds to requests from the client.

The role of the server program in an Ajax application is entirely specific to each Ajax application, but in general you will find that most Ajax server programs are responsible for looking up some piece of information and returning it to the client. For example, an Ajax employee directory application might pass an employee ID to the server, in which case the server program looks up the ID in a database and returns the employee's name and contact information. Or, as in the example you pondered in the previous chapter, information about an item to be shipped might be passed to the server, after which the server looks up the shipping rate and returns it.

Unlike on the client side of an Ajax application, which is exclusively the domain of JavaScript, the server side is wide open in terms of what programming language is used to create the server program. Fortunately, there are some popular options that are widely supported and relatively easy to modify and use. One of these options is PHP, which is a very popular server scripting language that is handy in creating Ajax applications. Similar to JavaScript code that is run on a browser, PHP code is run on a server. Referring back to Figure 2.1 once more, you can see how a PHP program on the server receives an Ajax request from the browser (thanks to JavaScript), and then responds after processing the request.

The interesting thing about PHP code, and all server-side scripts for that matter, is that they ultimately end up passing data back to the client. When working with PHP, you have to always keep in mind that whatever you're doing will culminate in data being shuttled back to the browser. In the case of an Ajax application, a PHP script is shuttling data back to an Ajax request.


ch02lev1sec2.html

The Ajax Request Lifecycle

Every Ajax request goes through a predictable lifecycle that is important to understand before you begin looking under the hood of Ajax applications. Each milestone in the Ajax lifecycle corresponds to a distinct state within the XMLHttpRequest object, which is the JavaScript object that serves as the heart of Ajax. The Ajax toolkit that you learn about in a moment shields you from the vast majority of the inner workings of the XMLHttpRequest object, but it's still worth getting acquainted with some facets of how it works. For a full dissection of the object, check out Appendix B, "A Quick and Dirty XMLHttpRequest Reference."

Following are the five states that an Ajax request cycles through as it goes from creation to submission to successful response:

  1. UNINITIALIZED—The request is uninitialized.

  2. LOADING—The request is initialized.

  3. LOADED—The request has been sent and is waiting for server acknowledgement.

  4. INTERACTIVE—The response data is being downloaded from the server.

  5. COMPLETE—The request/response cycle is complete.

The capitalized names for each state in the lifecycle correspond directly to internal states of the XMLHttpRequest object. The good news about this lifecycle is that you typically only concern yourself with the last state, COMPLETE, which makes sense given that you don't need to take any action until the request is finished and its resulting data is available. However, it's often helpful from a diagnostic perspective to peek into a transaction and make sure it is progressing as expected through the lifecycle. For this reason, the Ajax toolkit provided on the CD-ROM with this book includes a diagnostic feature that visually shows each state of an Ajax request as it takes place.

Note

Given the nature of the Booker sample application, you might think that this is a perfect opportunity for a synchronous application since there isn't much to do but wait around for the book to load. But what if you change your mind while the book is being downloaded? It would be much better if the user interface didn't lock you out of another selection while the loading is taking place. By using Ajax, you are perfectly free to choose another book while one book is loading. In this case, the current Ajax request is cancelled and the second book immediately begins loading.

Figure 2.2 shows an Ajax sample application called Booker as it is in the midst of carrying out a request. The Booker sample application is a simple e-book viewer.

Figure 2.2. A diagnostic bar along the top of the page shows the status of the Ajax request in the book viewer example.

[View full size image]

In this example, the entire text of the book War of the Worlds, by H. G. Wells, is being loaded and displayed via an Ajax request. Since the book is several hundred kilobytes in size, it takes a moment for the request to complete, depending upon connection speed of course. Figure 2.2 shows the application in the INTERACTIVE ("Downloading response...") state, which means the server response (the book text) is being downloaded. Notice that the area where the book text is to appear contains the message "Loading..." to indicate that there is a reason why nothing appears just yet. A few moments later, the request state changes to COMPLETE ("Request complete!") and the book text appears on the main part of the page (see Figure 2.3).

Figure 2.3. The complete text of the e-book appears once the request completes.

[View full size image]

Note

All of the books used in this example are public domain books that have been made available electronically by Project Gutenberg, a producer of free electronic books. To learn more, visit Project Gutenberg online at http://www.gutenberg.org/.

You might have noticed an e-book selection list near the top of the page just beneath the Ajax diagnostic bar. Not only does this allow you to access different books, it also serves as a good way to watch as Ajax requests of varying lengths take place. To test out what I'm talking about, open the booker.html page in the chap02 folder on the accompanying live Linux CD. The initial book loaded in the viewer is Alice's Adventures in Wonderland, by Lewis Carroll. Click the selection list and select War and Peace. Widely regarded as one of the heftiest novels ever written, the raw text for War and Peace by Leo Tolstoy weighs in at around 3MB. Even with the relative quickness of performing an Ajax request directly from a CD-ROM, you will notice the state change in the Ajax diagnostic bar.

Note

As you progress through the book, you'll have the option of turning the Ajax diagnostic bar on and off in each application based upon whether or not you care to monitor the request status.


ch02lev1sec3.html

Getting to Know the Ajax Toolkit

I have now made several references to the Ajax toolkit that is supplied on the CD-ROM with this book—now it's time to learn exactly what it is and how it works. As you will eventually find out if you do much of your own Ajax development, there are literally dozens if not hundreds of Ajax libraries out there designed to make using Ajax easier and more efficient. And many of these libraries live up to their goals. Problem is, many of them have about as much learning curve as Ajax itself, which is not a good thing unless you're building a monstrous Ajax application with lots of bells and whistles. And in that case, you may end up wanting to build your own Ajax library anyway.

To keep things as simple and straightforward as possible, I opted to build my own custom Ajax library for use in this book, and it should serve as your starting point for incorporating Ajax features into your Web pages. In many cases, you can reuse my code verbatim to get instant results. Beyond that, you may want to brush up on JavaScript and XML to take my code to another level. Either way, my Ajax toolkit serves as a handy jumpstart to Ajax Web development that has a very low learning curve.

My handy-dandy Ajax toolkit consists of several JavaScript files, each of which contains JavaScript functions and related helper code:

  • ajaxkit.js—Core Ajax

  • domkit.js—DOM (Document Object Model)

  • modalimgkit.js—Modal images

  • validatekit.js—Data validation

  • infowinkit.js—Information windows

  • ratingkit.js—Five-star ratings

By "helper code," I mean that these files offer pre-built code that is intended to make certain tasks dramatically easier. Not all of these files are included in every Ajax-powered Web page that you develop—you use them on an as-needed basis. As an example, following is the code used to import the first two files into a page, which must be placed in the <head> of the page:

<script type="text/javascript" src="ajaxkit.js"> </script>
<script type="text/javascript" src="domkit.js"> </script>

Once these lines of code have been added to your page, you are free to use any of the features supplied by the files within the Ajax toolkit.

The next few sections explore the different parts of the Ajax toolkit in more detail. Although I quickly explain all of the different JavaScript functions within each toolkit file, it isn't critical that you commit them to memory or even understand fully what their role is. The goal for now is just to let you know generally what each part of the toolkit offers—the remainder of the book revisits the toolkit in more detail when each piece of the puzzle comes into play.

The ajaxkit.js File

The ajaxkit.js portion of the toolkit consists solely of two JavaScript functions that handle submitting an Ajax request and updating the Ajax diagnostic bar, respectively:

ajaxSendRequest(type, url, handler, postDataType, postData)
ajaxUpdateState()

If you aren't familiar with JavaScript functions, just know that they are reusable chunks of code that carry out a specific task. In this case, the ajaxSendRequest() function sends an Ajax request to the server based upon information supplied in its five parameters. Again, it's not critical that you understand what function parameters are just yet—you'll get to know them as you see how the ajaxSendRequest() function is used in actual sample applications. For now, just know that the five parameters correspond to the type of Ajax request (GET or POST), the address of the server program that is processing the request, the custom function you provide that is handling the server response, and optional data type and data if the request is a POST.

Note

The type of Ajax request (GET or POST) flows directly from the fact that an Ajax request is really just an HTTP request. If you've ever worked with forms in HTML, you should have some familiarity with GET and POST requests. In general, the idea is that you use a GET request if you're just getting information from the server, whereas POST is intended more for passing information to the server.

Just to show that the ajaxSendRequest() function isn't too terribly difficult to use, here's the exact Ajax request used in the Booker e-book viewer example:

ajaxSendRequest("GET", "book_" + title + ".txt", handleRequest);

Even without getting deep into JavaScript, it isn't too terribly difficult to see that the first parameter indicates that this is a GET request, the second parameter is assembling a filename for the book, as in book_alicewonderland.txt, and the last parameter is the name of a custom handler function. You'll come back to this code a bit later in the chapter.

The ajaxUpdateState() function is used to update the Ajax diagnostic bar that you saw in Figures 2.2 and 2.3. You'll end up making a call to this function in the custom handler function that you create to respond to requests, like this:

ajaxUpdateState();

Making a call to a JavaScript function simply means that you're telling the function to do whatever task it was designed to do. A handler function is simply a function that is called in response to something happening. For example, a mouse click event handler function gets called whenever a mouse click occurs. Similarly, every Ajax application has a custom request handler function that gets called whenever the state of the request changes. That's why it was so important for you to learn about the request states a bit earlier in the chapter. You revisit request states and find out exactly how they fit into the Ajax toolkit equation in the section "Dismantling the E-Book Viewer."

The domkit.js File

Getting back to the pieces and parts of the Ajax toolkit, the domkit.js file contains several functions that carry out different DOM tasks. For example, the replaceText() function is responsible for changing the text of an element on the page:

replaceText(elem, text)

If you've done any JavaScript programming before, you may be familiar with the innerHTML property of most HTML elements, which is used to change the value of an element on the page. The usage of this property is considered passé by modern Web standards, and you're now encouraged to use newer features of the DOM to carry out a change in an element's contents in most cases. However, this newer approach is not as simple as setting a single property. Rather than have you reproduce line after line of unnecessary code, I opted to create a function called replaceText() that does the content replacement for you. You hand it the element and the new contents for it, and the replaceText() function does the rest. As an example, the following line of code changes the contents of the element stored in firstName to "Michael":

replaceText(firstName, "Michael");

You'll see this function used quite a lot throughout the examples in the book. As long as you import the domkit.js file into your pages, you are free to use the function as well. Don't worry, you see exactly how to import the file and use the replaceText() function when the examples roll around, so it's not critical to understand it fully at this stage.

Similar to replaceText() is the getText() function, which uses the DOM to extract the contents of an HTML element:

getText(elem);

You give this function an HTML element and it returns to you the contents of the element.

The domkit.js file also contains four functions for determining the size of the client area of the browser window, which can be very handy when carefully placing elements on the page:

getClientWidth()
getClientHeight()
getClientLeft()
getClientTop()

These functions return the width, height, left position, and top position of the browser's client area, which is the area where a page actually resides. In other words, it doesn't include the various toolbars, status bars, and other gadgets that surround a page.

The last function in the domkit.js file is used to obtain the data associated with a cookie that has been stored by the browser:

getCookieData(cookieName)

This function accepts the name of the cookie in question and then returns to you the cookie value. Cookies are a handy way to remember something the user has done on a page, and they come into play in this book in Chapter 12, "Adding an Ajax-Powered Rating System to Your Site," when you build a five-star rating application.

The modalimgkit.js File

The modalimgkit.js part of the toolkit consists of a single JavaScript function that adds modal image support to a Web page:

initModal()

You learn a great deal more about modal images in Chapter 8, "A Killer Interface for Image Viewing," but the general idea is to allow you to view a full-sized image from a thumbnail without having to load a new page into the browser. Similar to an About dialog box that might appear over an application window, a modal image pops up and appears over the current Web page.

The validatekit.js File

The validatekit.js portion of the toolkit offers several valuable functions for validating different types of user input:

validateNonEmpty(inputControl, helpControl)
validateInteger(inputControl, helpControl)
validateNumber(inputControl, helpControl)
validateZipCode(inputControl, helpControl)
validatePhone(inputControl, helpControl)
validateEmail(inputControl, helpControl)
validateDate(inputControl, helpControl)

These functions are all geared toward validating a specific data type, and most common data types you would encounter in a form are addressed. The two parameters to the functions are the input control to be validated and an output element where a help message is displayed when a validation problem is detected.

The infowinkit.js File

The infowinkit.js part of the toolkit contains functions used to add an Ajax-powered information popup window to a page:

initInfoWindow(width, height) {
showInfoWindow(infoURL, evt)

The first function is called initially to set the width and height of the information window, while the second function actually displays an information window with content from the specified URL.

The ratingkit.js File

The ratingkit.js portion of the toolkit implements a five-star rating system that can be added to any site, including adding rating support for multiple items:

initRatings()
setRating(id, rating)

The first function is used to initialize the rating system, while the second function sets the rating for a specific item. Each item within the rating system is assigned a unique ID, which is the first thing passed into the setRating() function. The second piece of information is the rating itself, which is in the range 1 to 5.


ch02lev1sec4.html

Dismantling the E-Book Viewer

It's time to quit playing around in the hypothetical world of Ajax theory and get into something real. The remainder of this chapter explores the inner workings of the Booker e-book viewer that you saw back in Figures 2.2 and 2.3, and explains exactly how it works. You can think of this section as a mini version of what each upcoming chapter is—a dissection of a real-world Ajax application that can be readily reused for your own purposes. Although I can't guarantee you'll understand every line of code without some JavaScript experience, I can definitely point you to the relevant places where you can make educated changes to customize the code to suit your own needs. In other words, I won't necessarily teach you how to be a mechanic, but I will tell you where to turn the wrench.

Earlier in this chapter I explained how every Ajax application ultimately boils down to two parts—a JavaScript program on the client (browser) side and a server-side program that is responsible for responding to Ajax requests. Although the server-side program can be written in any number of languages, this book focuses on PHP for the vast majority of examples. The good news is that PHP is a simple enough language that you don't have to know PHP to be able to make out the sample code and make isolated changes for customization.

The Booker example is somewhat unique in that it doesn't require any custom development on the server side. Since all the Ajax request is doing is loading an entire e-book text file from the Web server, the server itself is all that is needed. If the application were plucking a portion of a book, such as an individual chapter, then you might need to develop a custom program on the server.

Of course, the client still needs some custom programming that must respond to the user selecting an e-book from the selection list. This custom code must then load the e-book from the server asynchronously and display it on the page. In many ways, this is the most basic of all Ajax requests because you don't need to pass any information to the server—you just specify the name of the e-book text file when making the Ajax request. More on this detail in a moment; let's first revisit the e-books.

The E-Books

In the Booker example, the e-books are provided as raw text files with a familiar .txt file extension. You can open and edit these files just like any other text files using Vi, Emacs, or Pico on Linux systems, Notepad on Windows systems, or TextEdit on the Mac. The following books and their associated text files are included with the sample application:

  • Alice's Adventures in Wonderland—book_alicewonderland.txt

  • Frankenstein—book_frankenstein.txt

  • Moby Dick—book_mobydick.txt

  • War and Peace—book_warandpeace.txt

  • The War of the Worlds—book_warofworlds.txt

You may notice a very clear pattern in the naming of the e-book text files in that they all follow the form book_AbbrevTitle.txt, where AbbrevTitle is the abbreviated title of the book. By following a standard format for the e-book filenames, it becomes much easier to programmatically load each book in response to the user making a selection from the selection list on the page. More specifically, you can build a filename programmatically using the following equation:

"book_" + AbbrevTitle + ".txt"

As you see in a moment, this is in fact exactly how the code works that handles loading an e-book in response to a change in selection.

The Booker Web Page

All of the heavy lifting in the Booker sample application takes place in the booker.html Web page, which contains HTML and JavaScript code, along with a few CSS styles here and there. Before digging into the code, however, let's take one more look at the application in action in Figure 2.4, this time with the e-book Frankenstein loaded.

Figure 2.4. The complete text of the e-book appears once the request completes.

[View full size image]

Although the JavaScript code occurs near the beginning of the actual HTML document, it makes more sense to take a look at the body HTML code first:

Code View:
<body style="background:#EEEEEE"
  onload="document.getElementById('book').selectedIndex = 0;
  loadBook(document.getElementById('book').options[
  document.getElementById('book').selectedIndex].value)">
  <div id="ajaxState" style="display:block"></div>
  <br />
  <div style="margin-left:10%">Select book:
    <select id="book" onchange=
      "loadBook(this.options[this.selectedIndex].value)">
      <option value="alicewonderland">Alice's Adventure's in
        Wonderland by Lewis Carroll</option>
      <option value="frankenstein">Frankenstein by Mary
        Shelley</option>
      <option value="mobydick">Moby Dick by Herman
        Melville</option>
      <option value="warandpeace">War and Peace by Leo
        Tolstoy</option>
      <option value="warofworlds">The War of the Worlds by H.G.
        Wells</option>
    </select>
  </div>
  <br />
  <div id="booktext" style="margin-left:10%; margin-right:10%;
    padding:2%; background:#FFFFFF; border:thin solid #333333">
    </div>
</body>

The bulk of this code consists of the e-book selection list, which appears within the <select> tag. Notice that the abbreviated title of each book is specified as the value attribute of each e-book's <option> tag. This is how the JavaScript code is able to assemble the name of a book's text file (book_alicewonderland.txt) from its value in the selection list (alicewonderland).

Moving down the page a bit, you'll see a div element with an ID of booktext. This is the div element that holds the text contents of an e-book after it is loaded via an Ajax request. In other words, this div is the main area of the page. The various CSS styles applied to the div are what align it in the center of the page, space the text in a little from the edges, and give it a visible border. The ID of this div element is used in the JavaScript code for the page to set the e-book text after it has been loaded through an Ajax request.

Looking back for a second at the selection list, perhaps the most critical piece of code in the page is the onchange event handler for the selection list, which contains the following line of JavaScript code:

loadBook(this.options[this.selectedIndex].value)

This is the code that loads an e-book based upon a selection change in the selection list. The code is passing the value of the currently selected e-book to the custom loadBook() function. Here's the code for that function:

function loadBook(title) {
  replaceText(document.getElementById("booktext"), "Loading...");
  ajaxSendRequest("GET", "book_" + title + ".txt", handleRequest);
}

Ah, two familiar functions! If you recall from the earlier discussion of the Ajax toolkit, the replaceText() and ajaxSendRequest() functions were both explained. As a little refresher, the replaceText() function is used to set the contents of any HTML element. In this case, it is being used to set the main div element (booktext) to the text "Loading..." so that the user knows that the e-book is being loaded. The actual Ajax request is initiated by the ajaxSendRequest() function, which uses the GET request method. The second parameter to the ajaxSendRequest() function is the filename of the e-book to load, which has the form book_AbbrevTitle.txt. And finally, the last parameter is the custom handler function that is called when the Ajax request is completed (i.e., the e-book finishes loading).

OK, if that last paragraph felt like a technical punch in the mouth, I readily apologize. I don't entirely expect you to follow every nuance of this code as quickly as I've thrown it at you. As you see more Ajax applications, it will all start to feel much more natural and familiar. The good news is that in the meantime, you only need to understand a few critical points in the code to make customizations for your own purposes. We'll get to that in the next section.

The next big stop in this whirlwind examination of the Booker application is the handleRequest() function, which is the custom function that is called when an Ajax request completes. Here's the code for it:

function handleRequest() {
  if (request.readyState == 4 && request.status == 200) {
    replaceText(document.getElementById("booktext"),
      request.responseText);
  }
  ajaxUpdateState();
}

Hopefully this code is a little simpler than you were expecting. The first line of code within the function checks to make sure that the request finished successfully. This involves looking at the values of the readyState and status properties of the request object. This is very standard Ajax code that you will see reproduced verbatim in every Ajax application. The specific values being checked are directly related to the standard XMLHttpRequest object, which is covered in great detail in Appendix B. Feel free to study that appendix to find out more about how the Ajax toolkit works under the hood. For now, however, just know that the if statement is simply checking to make sure the request finished up without a problem.

Within the if statement, the replaceText() function is called to set the main div element (booktext) on the page to the e-book text that was just loaded. The key to this code is the responseText property of the request object, which contains the response data from the request. You'll always use the responseText property for raw text data or the responseXML property for XML data when handling the results of an Ajax request.

The last line of meaningful code in the handleRequest() function is a call to the ajaxUpdateStatus() function, which updates the Ajax diagnostic bar. It is very important that this function remain outside of the if statement so that it gets called every time the state of the XMLHttpRequest object changes. One thing I haven't mentioned is that this function requires a special div element to be placed on the page. If you look back at the HTML code for the Booker application page, you'll see a div element that is coded like this:

<div id="ajaxState" style="display:block"></div>

The ajaxUpdateStatus() function looks for a div element with an ID of ajaxState, and then sets the background color and content of the div accordingly. To hide the Ajax diagnostic bar, just change the style property of the div element to display:none. You can then show the diagnostic bar again later if necessary by changing the style back to display:block. When you are finished developing an Ajax application and are ready to completely eliminate the diagnostic bar, just remove the div entirely, as well as the call to ajaxUpdateStatus().

One bit of housekeeping that I've yet to explain is the onload event handler for the body element, which is very important because it establishes which e-book is initially selected, and also makes sure the book gets loaded properly. Here's the code that is set in the onload event handler:

document.getElementById('book').selectedIndex = 0;
loadBook(document.getElementById('book').options[
  document.getElementById('book').selectedIndex].value);

The first line sets the selected item in the selection list to the first item in the list (item 0). You use 0 for the first item because the indexing of selection lists starts at 0 and counts up. If you wanted to select the second item, you would set the selectedIndex property to 1.

The second and third lines of code are really just one line of code carried across two lines because it's so long. The code is made a bit messier because of the need to use the getElementById() function twice to get the selection list object. The code is much easier to understand if you replace the getElementById() function calls with a name. Here's a simplification of the code with this selection list object renamed sel:

sel.selectedIndex = 0;
loadBook(sel.options[sel.selectedIndex].value);

Now, hopefully, you can see how the loadBook() function is passed the value of the currently selected e-book. Or more specifically, it is passed the abbreviated title of the currently selected e-book. And if you recall from earlier in this discussion, the loadBook() function uses this abbreviated title to build a filename for the e-book and pass it along as part of the Ajax request.


ch02lev1sec5.html

Customizing the E-Book Viewer

I know, there's a good chance the last few pages have made you question all this Ajax stuff and whether it's really worth the headache. Again, I have to reiterate that the goal here is to just get your feet wet, not to present you with a trial-by-fire tutorial on Ajax. Remember that the premise of this book is to present you with plug-and-play Ajax applications and components that you can reuse in your own Web pages with minimal effort. As it turns out, this minimal effort sometimes requires some minor JavaScript tweaking, which is why I wanted you to go ahead and see some code early.

Speaking of reusing code in your own Web pages, have you had time to think about how the Booker application might be useful for any of your own projects? Think about it this way: Even though the application in its current form is being used as a rudimentary e-book viewer, what's really going on is that it allows the user to select and load large text documents dynamically. So any application that involves the selection of unwieldy text documents would be an ideal candidate for a similar Ajax solution. Maybe it's an archival Web site containing lots of archived documents, or maybe your company stores proposals, processes, or contracts as raw text that would be more easily accessed through such an Ajax interface. If so, you might want to consider customizing the Booker sample application for your own needs.

Here is a list of ways you can modify the application with relatively little effort:

  • Add more content— You can easily expand the content of the application dramatically by copying new e-book text files to the Web server and then adding a new selection list option for each new book. Just make sure that the value attribute of each <option> tag (warofworlds, for example) matches the abbreviated title of the book you use in the filename of the text file (book_warofworlds.txt).

  • Change the rendering of the e-book content— If you want to make the e-books a bit more accessible to all readers, you may want to consider increasing the font size and maybe even choosing a different font that is more suitable for reading. Since all of the book content flows into the div element with the ID booktext, you can easily alter the appearance of an entire book by adding some CSS font styles to that div element.

  • Turn off the Ajax diagnostic bar— Don't forget to turn off the Ajax diagnostic bar before releasing your application to the public. To do so, just remove the div element with the ID of ajaxState from the HTML part of the page, and then remove the line of code in the JavaScript handleRequest() function that calls the ajaxUpdateState() function.

If you're thinking another cool tweak to the Booker application might be to load and display each e-book one chapter at a time, then you're certainly on to something because the next chapter tackles exactly that challenge.


ch02lev1sec6.html

Summary

Indeed, this chapter shifted things into high gear pretty quickly. You started off with a gingerly stroll through the pieces and parts of the Ajax machine, learned a few things about the lifecycle of an Ajax request, and then put the pedal to the metal in getting a rapid-fire introduction to the Ajax toolkit and a downright jarring introduction to your first complete Ajax application. All I can say is that things only get better from here. Sure, the applications build and get a little trickier here and there, but you'll start to see some very common threads among all Ajax applications.


part02.html

Part II: Building Real-World Ajax Applications

Chapter 3 Dynamically Loading Web Data: An XML E-Book Viewer

Chapter 4 Using Ajax to Dynamically Populate Lists: A Stock Picker

Chapter 5 Tapping into RSS News Feeds

Chapter 6 Reading the User's Mind with Auto-Complete

Chapter 7 Creating Responsive GUIs with Real-Time Validation

Chapter 8 A Killer Interface for Image Viewing

Chapter 9 Presenting Information with Slick Popups

Chapter 10 Forecasting the Weather with Ajax

Chapter 11 Building an Ajax Shipping Calculator

Chapter 12 Adding an Ajax-Powered Rating System to Your Site

Chapter 3. Dynamically Loading Web Data: An XML E-Book Viewer

Ajax in the Arcade

The Web isn't the first time the term Ajax has been associated with interactivity and computing. In 1987 Konami released a vertically scrolling space shoot-'em-up video game of the same name. In Ajax the video game you alternate between controlling a helicopter and a fighter jet, and fire various types of missiles, lasers, and bombs.

The previous chapter explored the basics of loading data dynamically with Ajax, but the e-book example was fairly inefficient since it required you to wait for an entire book to load before being able to read anything. The Booker application also only demonstrated how to load a raw text file, which doesn't do much in the way of addressing the XML part of the Ajax equation. It actually makes more sense to deal with e-books in XML form, which gives you the ability to pick and choose what information you want to process. More specifically, it is relatively straightforward to access an XML e-book on a chapter-by-chapter basis, thereby shortening the transfer time of each Ajax request and improving the readability of the book by only displaying one chapter at a time.

This chapter builds upon the Booker example in the previous chapter by guiding you through a redesign of the application using XML as the e-book data format. In addition to seeing how XML fits into a practical Ajax application, you get a feel for how much more responsive an application becomes when you reduce the amount of data being exchanged per request.

The following files are used by the Booker application in this chapter, and are located on the live Linux CD-ROM with the book in the chap03 example code folder:

  • booker.html—Main Web page

  • booker.php—Server script for loading a chapter from an e-book

  • ajaxkit.js—Core Ajax functions for the Ajax Toolkit

  • domkit.js—DOM-related functions for the Ajax Toolkit

  • book_alicewonderland.xml—Alice's Adventures in Wonderland XML e-book

  • book_frankenstein.xml—Frankenstein XML e-book

  • book_mobydick.xml—Moby Dick XML e-book

  • book_warandpeace.xml—War and Peace XML e-book

  • book_warofworlds—War of the Worlds XML e-book

The Challenge: Loading Data in Smaller Chunks

If you took a month hiatus from reading this book after the last chapter in an attempt to read the War and Peace e-book, then you quickly found out that the Booker sample application is a bit lacking in performance. The problem is that the application deals with an e-book as one huge chunk of raw text, which is quite cumbersome when you attempt to read a truly hefty book such as War and Peace, which weighs in at just over 3MB. I don't know about your Internet connection, but even my broadband connection grunts and moans and takes its sweet time when loading a 3MB text file.

Not only is the transfer time a problem with the original Booker application, but there is a serious usability problem inherent in trying to display an entire book on a single page. Think about it this way—a physical printed book is first broken down into chapters and then further broken down into pages. Not only does this provide you with a great place to put a bookmark to remember your location within a book, but it serves as a helpful mental break to turn the page after reading a good-sized block of text. Not so with Booker. An entire 3MB novel is crammed into one big fat virtual page in your browser. Unless you're some kind of superhuman speed reader, you will hate this approach to reading almost immediately.

So we've assessed that the first Booker application has some problems, and in the spirit of dynamic data loading, surely Ajax offers a solution. Indeed, with a little Ajax help it is possible to dynamically load only what you need, which in the case of an e-book is just a single chapter. You're killing two birds with one stone with this change because the new approach of loading a chapter of book data at a time yields significant performance improvements due to the dramatically smaller amount of data being shuttled across in each Ajax request. The challenge then is to develop a new-and-improved version of Booker that loads one chapter at a time.

Note

It wouldn't be out of the question to consider breaking down an e-book into individual pages, as opposed to just chapters. However, what would define the length of a page? Physical printed books certainly don't adhere to the same number of pages when printed in different sizes and fonts. Web browsers are even more diverse in terms of how much information they can display. For this reason, it makes sense to focus on a chapter as the unit of measure for breaking down e-books into component parts. Later on if you want to paginate a chapter programmatically to fit a particular browser window for better readability, that's perfectly fine. But for the purposes of organizing and loading an XML e-book, chapters are the way to go.

Before we move on to the design phase of the new e-book viewer application, it's worth taking a brief step back to reassess the original Booker application and see how it works. By doing so, you'll have a more accurate picture of the challenge you're facing in the design of the new application.

First off, Figure 3.1 shows how the main Booker HTML Web page contains a selection list with the available e-books. Choosing a book from the selection list results in the entire contents of the book loading into the area (div) just below the list, which occupies most of the page.

Figure 3.1. The original Booker application loads the entire text of an e-book when the user chooses the book from a list.

[View full size image]

Behind the scenes, the Booker Web page is using an Ajax request to dynamically load the book text in response to the user choosing it in the list. From an Ajax perspective, the original Booker application represents perhaps the simplest of all Ajax requests in that it is dealing with unformatted data (raw text) and the data is obtained directly from a file on the server (an e-book text file); no special server program is required to process the data before responding to the request.

The challenge going into the new version of Booker is to first reformat the e-books as highly structured XML documents and then rework the Web page to be able to load a single chapter as opposed to an entire book. This will also involve some user interface changes since the user will now need to be able to navigate between chapters in a book. It turns out that this seemingly subtle change in data format has a significant impact on the design and implementation of the Booker application.


ch03.html

Part II: Building Real-World Ajax Applications

Chapter 3 Dynamically Loading Web Data: An XML E-Book Viewer

Chapter 4 Using Ajax to Dynamically Populate Lists: A Stock Picker

Chapter 5 Tapping into RSS News Feeds

Chapter 6 Reading the User's Mind with Auto-Complete

Chapter 7 Creating Responsive GUIs with Real-Time Validation

Chapter 8 A Killer Interface for Image Viewing

Chapter 9 Presenting Information with Slick Popups

Chapter 10 Forecasting the Weather with Ajax

Chapter 11 Building an Ajax Shipping Calculator

Chapter 12 Adding an Ajax-Powered Rating System to Your Site

Chapter 3. Dynamically Loading Web Data: An XML E-Book Viewer

Ajax in the Arcade

The Web isn't the first time the term Ajax has been associated with interactivity and computing. In 1987 Konami released a vertically scrolling space shoot-'em-up video game of the same name. In Ajax the video game you alternate between controlling a helicopter and a fighter jet, and fire various types of missiles, lasers, and bombs.

The previous chapter explored the basics of loading data dynamically with Ajax, but the e-book example was fairly inefficient since it required you to wait for an entire book to load before being able to read anything. The Booker application also only demonstrated how to load a raw text file, which doesn't do much in the way of addressing the XML part of the Ajax equation. It actually makes more sense to deal with e-books in XML form, which gives you the ability to pick and choose what information you want to process. More specifically, it is relatively straightforward to access an XML e-book on a chapter-by-chapter basis, thereby shortening the transfer time of each Ajax request and improving the readability of the book by only displaying one chapter at a time.

This chapter builds upon the Booker example in the previous chapter by guiding you through a redesign of the application using XML as the e-book data format. In addition to seeing how XML fits into a practical Ajax application, you get a feel for how much more responsive an application becomes when you reduce the amount of data being exchanged per request.

The following files are used by the Booker application in this chapter, and are located on the live Linux CD-ROM with the book in the chap03 example code folder:

  • booker.html—Main Web page

  • booker.php—Server script for loading a chapter from an e-book

  • ajaxkit.js—Core Ajax functions for the Ajax Toolkit

  • domkit.js—DOM-related functions for the Ajax Toolkit

  • book_alicewonderland.xml—Alice's Adventures in Wonderland XML e-book

  • book_frankenstein.xml—Frankenstein XML e-book

  • book_mobydick.xml—Moby Dick XML e-book

  • book_warandpeace.xml—War and Peace XML e-book

  • book_warofworlds—War of the Worlds XML e-book

The Challenge: Loading Data in Smaller Chunks

If you took a month hiatus from reading this book after the last chapter in an attempt to read the War and Peace e-book, then you quickly found out that the Booker sample application is a bit lacking in performance. The problem is that the application deals with an e-book as one huge chunk of raw text, which is quite cumbersome when you attempt to read a truly hefty book such as War and Peace, which weighs in at just over 3MB. I don't know about your Internet connection, but even my broadband connection grunts and moans and takes its sweet time when loading a 3MB text file.

Not only is the transfer time a problem with the original Booker application, but there is a serious usability problem inherent in trying to display an entire book on a single page. Think about it this way—a physical printed book is first broken down into chapters and then further broken down into pages. Not only does this provide you with a great place to put a bookmark to remember your location within a book, but it serves as a helpful mental break to turn the page after reading a good-sized block of text. Not so with Booker. An entire 3MB novel is crammed into one big fat virtual page in your browser. Unless you're some kind of superhuman speed reader, you will hate this approach to reading almost immediately.

So we've assessed that the first Booker application has some problems, and in the spirit of dynamic data loading, surely Ajax offers a solution. Indeed, with a little Ajax help it is possible to dynamically load only what you need, which in the case of an e-book is just a single chapter. You're killing two birds with one stone with this change because the new approach of loading a chapter of book data at a time yields significant performance improvements due to the dramatically smaller amount of data being shuttled across in each Ajax request. The challenge then is to develop a new-and-improved version of Booker that loads one chapter at a time.

Note

It wouldn't be out of the question to consider breaking down an e-book into individual pages, as opposed to just chapters. However, what would define the length of a page? Physical printed books certainly don't adhere to the same number of pages when printed in different sizes and fonts. Web browsers are even more diverse in terms of how much information they can display. For this reason, it makes sense to focus on a chapter as the unit of measure for breaking down e-books into component parts. Later on if you want to paginate a chapter programmatically to fit a particular browser window for better readability, that's perfectly fine. But for the purposes of organizing and loading an XML e-book, chapters are the way to go.

Before we move on to the design phase of the new e-book viewer application, it's worth taking a brief step back to reassess the original Booker application and see how it works. By doing so, you'll have a more accurate picture of the challenge you're facing in the design of the new application.

First off, Figure 3.1 shows how the main Booker HTML Web page contains a selection list with the available e-books. Choosing a book from the selection list results in the entire contents of the book loading into the area (div) just below the list, which occupies most of the page.

Figure 3.1. The original Booker application loads the entire text of an e-book when the user chooses the book from a list.

[View full size image]

Behind the scenes, the Booker Web page is using an Ajax request to dynamically load the book text in response to the user choosing it in the list. From an Ajax perspective, the original Booker application represents perhaps the simplest of all Ajax requests in that it is dealing with unformatted data (raw text) and the data is obtained directly from a file on the server (an e-book text file); no special server program is required to process the data before responding to the request.

The challenge going into the new version of Booker is to first reformat the e-books as highly structured XML documents and then rework the Web page to be able to load a single chapter as opposed to an entire book. This will also involve some user interface changes since the user will now need to be able to navigate between chapters in a book. It turns out that this seemingly subtle change in data format has a significant impact on the design and implementation of the Booker application.


ch03lev1sec1.html

Part II: Building Real-World Ajax Applications

Chapter 3 Dynamically Loading Web Data: An XML E-Book Viewer

Chapter 4 Using Ajax to Dynamically Populate Lists: A Stock Picker

Chapter 5 Tapping into RSS News Feeds

Chapter 6 Reading the User's Mind with Auto-Complete

Chapter 7 Creating Responsive GUIs with Real-Time Validation

Chapter 8 A Killer Interface for Image Viewing

Chapter 9 Presenting Information with Slick Popups

Chapter 10 Forecasting the Weather with Ajax

Chapter 11 Building an Ajax Shipping Calculator

Chapter 12 Adding an Ajax-Powered Rating System to Your Site

Chapter 3. Dynamically Loading Web Data: An XML E-Book Viewer

Ajax in the Arcade

The Web isn't the first time the term Ajax has been associated with interactivity and computing. In 1987 Konami released a vertically scrolling space shoot-'em-up video game of the same name. In Ajax the video game you alternate between controlling a helicopter and a fighter jet, and fire various types of missiles, lasers, and bombs.

The previous chapter explored the basics of loading data dynamically with Ajax, but the e-book example was fairly inefficient since it required you to wait for an entire book to load before being able to read anything. The Booker application also only demonstrated how to load a raw text file, which doesn't do much in the way of addressing the XML part of the Ajax equation. It actually makes more sense to deal with e-books in XML form, which gives you the ability to pick and choose what information you want to process. More specifically, it is relatively straightforward to access an XML e-book on a chapter-by-chapter basis, thereby shortening the transfer time of each Ajax request and improving the readability of the book by only displaying one chapter at a time.

This chapter builds upon the Booker example in the previous chapter by guiding you through a redesign of the application using XML as the e-book data format. In addition to seeing how XML fits into a practical Ajax application, you get a feel for how much more responsive an application becomes when you reduce the amount of data being exchanged per request.

The following files are used by the Booker application in this chapter, and are located on the live Linux CD-ROM with the book in the chap03 example code folder:

  • booker.html—Main Web page

  • booker.php—Server script for loading a chapter from an e-book

  • ajaxkit.js—Core Ajax functions for the Ajax Toolkit

  • domkit.js—DOM-related functions for the Ajax Toolkit

  • book_alicewonderland.xml—Alice's Adventures in Wonderland XML e-book

  • book_frankenstein.xml—Frankenstein XML e-book

  • book_mobydick.xml—Moby Dick XML e-book

  • book_warandpeace.xml—War and Peace XML e-book

  • book_warofworlds—War of the Worlds XML e-book

The Challenge: Loading Data in Smaller Chunks

If you took a month hiatus from reading this book after the last chapter in an attempt to read the War and Peace e-book, then you quickly found out that the Booker sample application is a bit lacking in performance. The problem is that the application deals with an e-book as one huge chunk of raw text, which is quite cumbersome when you attempt to read a truly hefty book such as War and Peace, which weighs in at just over 3MB. I don't know about your Internet connection, but even my broadband connection grunts and moans and takes its sweet time when loading a 3MB text file.

Not only is the transfer time a problem with the original Booker application, but there is a serious usability problem inherent in trying to display an entire book on a single page. Think about it this way—a physical printed book is first broken down into chapters and then further broken down into pages. Not only does this provide you with a great place to put a bookmark to remember your location within a book, but it serves as a helpful mental break to turn the page after reading a good-sized block of text. Not so with Booker. An entire 3MB novel is crammed into one big fat virtual page in your browser. Unless you're some kind of superhuman speed reader, you will hate this approach to reading almost immediately.

So we've assessed that the first Booker application has some problems, and in the spirit of dynamic data loading, surely Ajax offers a solution. Indeed, with a little Ajax help it is possible to dynamically load only what you need, which in the case of an e-book is just a single chapter. You're killing two birds with one stone with this change because the new approach of loading a chapter of book data at a time yields significant performance improvements due to the dramatically smaller amount of data being shuttled across in each Ajax request. The challenge then is to develop a new-and-improved version of Booker that loads one chapter at a time.

Note

It wouldn't be out of the question to consider breaking down an e-book into individual pages, as opposed to just chapters. However, what would define the length of a page? Physical printed books certainly don't adhere to the same number of pages when printed in different sizes and fonts. Web browsers are even more diverse in terms of how much information they can display. For this reason, it makes sense to focus on a chapter as the unit of measure for breaking down e-books into component parts. Later on if you want to paginate a chapter programmatically to fit a particular browser window for better readability, that's perfectly fine. But for the purposes of organizing and loading an XML e-book, chapters are the way to go.

Before we move on to the design phase of the new e-book viewer application, it's worth taking a brief step back to reassess the original Booker application and see how it works. By doing so, you'll have a more accurate picture of the challenge you're facing in the design of the new application.

First off, Figure 3.1 shows how the main Booker HTML Web page contains a selection list with the available e-books. Choosing a book from the selection list results in the entire contents of the book loading into the area (div) just below the list, which occupies most of the page.

Figure 3.1. The original Booker application loads the entire text of an e-book when the user chooses the book from a list.

[View full size image]

Behind the scenes, the Booker Web page is using an Ajax request to dynamically load the book text in response to the user choosing it in the list. From an Ajax perspective, the original Booker application represents perhaps the simplest of all Ajax requests in that it is dealing with unformatted data (raw text) and the data is obtained directly from a file on the server (an e-book text file); no special server program is required to process the data before responding to the request.

The challenge going into the new version of Booker is to first reformat the e-books as highly structured XML documents and then rework the Web page to be able to load a single chapter as opposed to an entire book. This will also involve some user interface changes since the user will now need to be able to navigate between chapters in a book. It turns out that this seemingly subtle change in data format has a significant impact on the design and implementation of the Booker application.


ch03lev1sec2.html

The Design: Designing an XML E-Book Viewer

OK, so you're revamping the Booker application to load e-books using an XML data format via Ajax requests. This means you'll first need to come up with a suitable XML format for the books that allows them to be readily accessed one chapter at a time. With the XML format figured out, you'll need to figure out what exactly is being transferred between the server and client during an Ajax request. It obviously stands to reason that chapter text will be sent along, but now that the e-books will be formatted more intelligently, you should be able to receive the chapter title as part of the request as well. Then you can display the name of the chapter as a heading above the chapter text, giving the page a little more of the feel of a real book.

Note

If you're not experienced with XML, don't worry because it is very easy to understand once you see it in action. In fact, you're indirectly already using XML when creating Web pages in HTML. HTML, or actually its more formal cousin XHTML, can be thought of as a specific application of XML.

The Client Request

So a big part of the design of the new-and-improved Booker application is figuring out exactly what information needs to move between client and server, and then back from server to client. You probably recall that each e-book is stored in its own file. In the first Booker application, the abbreviated title of the book is sent along as part of the Ajax request—this is how the request knows which file to open, which in turn determines the book that is loaded. In the newer version, you're no longer requesting an entire book but instead a single chapter of a book. For this reason, you'll also need to pass along the chapter in addition to the abbreviated title. To keep things simple and efficient, the chapter can be specified as a number, where 0 is the first chapter, 1 is the second chapter, and so on.

Note

Since many books contain "chapters" such as an introduction, prologue, epilogue, etc., it's better if you use a different terminology when referring to the "number" of a chapter with respect to loading a chapter from an XML document. It really makes more sense to call this number a chapter index instead. Therefore, if a book has an introduction and a prologue before Chapter 1, their chapter indexes would be 0, 1, and 2, respectively.

To summarize, the following two pieces of information must be sent from the client to the server to initiate an e-book request in the new version of the Booker application:

  • Abbreviated title (alicewonderland, for example)

  • Chapter index (0, for example)

Let's now shift our attention to the server side of things and find out what it has to do in response to receiving the client request.

The Server Response

The server's job is to take the abbreviated e-book title and chapter index, and respond with the chapter text and anything else that might be useful in the context of the client e-book viewer. You already know for certain that the chapter title would be a handy thing to know. However, some books go a step further by having both a chapter number and a chapter title. Knowing this, it's probably a good idea to receive the chapter number from the server as well. This also helps to account for the situation where there is a "chapter" that doesn't fall under the normal chapter designation, as in an introduction or epilogue. In this case, the "chapter number" might be "Introduction" instead of "Chapter 1."

Although you could stop here and be well on your way to a working e-book viewer with support for discrete chapters, a critical piece of information is still missing. To understand what is missing, it's important to assess how the user interface for the application will work. When you think about it, a physical book operates on the idea of turning pages. Even though the e-book viewer doesn't break down books into pages, the concept of moving through chapters like the flipping of pages is a good idea. This can be accomplished with Previous and Next buttons, as illustrated in Figure 3.2.

Figure 3.2. Previous and Next buttons provide an intuitive means of navigating through the chapters in an e-book.

[View full size image]

Notice in the figure how the chapters can be thought of as logically appearing one after the next. The Next and Previous buttons allow you to navigate from one chapter to the next in either direction. But how do you know when to stop? This seems like a trivial question, but it is very important because it reveals that you must know how many chapters there are in total to know when to disable the Next button. The Previous button is easier to handle because you already know which chapter is the first one. The last chapter is a trickier animal because you'd rather not have to read all of the chapters into the application and remember the name of the last one. The cleaner alternative is to return a total chapter count as part of the Ajax request.

With the total number of chapters in hand, you can simply compare the currently viewed chapter to the total number of chapters to see whether or not the Next button is usable. In other words, if the reader is already viewing the last chapter, you need to disable the Next button. The total number of chapters is the key piece of information that makes this user interface trick possible.

So recapping the server-to-client data transmission part of the Booker application, here's what is getting sent:

  • Chapter number (Chapter I, for example)

  • Chapter title (Down the Rabbit-Hole, for example)

  • Chapter text (Alice was beginning to..., for example)

  • Total number of chapters (12, for example)

With the server's response in mind, it's now possible to assemble the entire client-server conversation and dig a little deeper into exactly how the data is represented within it.

Making Sense of the Client-Server Conversation

Putting together the entire data-transfer circuit for the application gives you Figure 3.3, which shows the flow of information from client to server and then back from server to client, all of which is part of a single Ajax request.

Figure 3.3. The data flow between the client and server in an Ajax request is a critical part of the design of the Booker application.

The figure reveals how multiple pieces of information are being transferred back and forth between the client and server in both directions. You already know from the original Booker application that it's not difficult at all to send along information to the server as part of the URL for the Ajax request. For example, the abbreviated title of an e-book in the previous version of Booker was sent along using the following URL:

booker.php?title=alicewonderland

You can add the chapter index as a second parameter in the URL by separating it from the title with an ampersand (&), like this:

booker.php?title=alicewonderland&chapIndex=0

This covers the data transfer from client to server. The data coming back from server to client is a lot trickier since it contains the entire text for a chapter, along with other book information, including the chapter number, chapter title, and total number of chapters. This data requires fairly sophisticated formatting to ensure that it can be extracted cleanly back on the client. It turns out that XML offers a perfect solution for formatting this data. Even if you aren't an XML guru, I don't think you'll have too much trouble deciphering the following code:

<bookData>
  <chapNum>Chapter I</chapNum>
  <chapTitle>Down the Rabbit-Hole</chapTitle>
  <chapText>Alice was beginning to get very tired of sitting by
  her sister on the bank, and of having nothing to do...
  </chapText>
  <totalChapters>12</totalChapters>
</bookData>

Note

There is nothing standard or official about any of this XML code. It was created purely for the purposes of the Booker application. One of the key benefits of XML is that it allows you to create any language you want for any purpose. Knowing this, you could easily rename the <bookData> tag to <eBookInfo> or <booker>, as long as you use the tag name consistently throughout all of the application code.

As you can see, the chapter information included in the server response is coded using XML tags that clearly describe each piece of information. The chapter text was deliberately pared down in this example to make the code easier to read.

So the server responds to the client's Ajax request with XML data that includes the relevant information about the chapter. It then becomes the client's job to parse the XML data and display it on the page. You find out exactly how this is done a little later in the chapter. Before that, however, it's important to cover one additional design issue: the need for a server script.

A critical part of the design of the new Booker application is the coding of each e-book as an XML document. Since each e-book contains numerous chapters, along with other information such as the title and author of the book, it stands to reason that there must be some kind of program on the server that knows how to take a chapter request and respond with the XML chapter data you saw a moment ago. This server program (PHP script, in this case) is responsible for parsing through the XML data for a complete e-book, extracting the specified chapter number, chapter title, and chapter text, and also counting the total number of chapters in the book. The script must then package this information up into XML code of its own and return it to the browser. This is the same code you saw earlier that included the <bookData> tag.

You now have enough knowledge of the Ajax request/response for the new Booker application to go ahead and put the application together. If you're a little apprehensive about jumping into XML so quickly, don't worry about it. It takes surprisingly little code to load and make sense of XML data. Besides, the cool thing about having an XML data-driven application is that you don't have to screw around with the application code much (if any) once it's built—you can make significant changes by simply altering the XML for the e-books themselves.


ch03lev1sec3.html

Putting Together the E-Book Viewer

The best way to begin constructing the hopped up Booker application is to break it down into its pieces and parts. Following are the three major components that go into the application:

  • XML files (book_alicewonderland.xml, book_frankenstein.xml, etc.)

  • HTML Web page (booker.html)

  • PHP server script (booker.php)

The next few sections explore these pieces of the Booker puzzle in more detail, revealing the code that makes them work.

Note

Yikes! Another new technology to learn—PHP. Not so. Although knowing PHP is certainly a huge benefit, you absolutely don't have to be a PHP programmer to understand and customize this application or any of the others in this book, for that matter. I have deliberately structured any and all PHP code in the sample applications to be extremely simple and minimal. Much of the PHP code you encounter is "boilerplate" code, meaning that you don't need to touch it to make tweaks and customizations to an application. When an opportunity arises to fine-tune the PHP code, I show you exactly where and why.

The XML E-Books

In the original Booker example, the e-books are specified as raw text files with a familiar .txt file extension. The application opens and displays all of the data for each e-book as one huge chunk of text. The new Booker application expects e-books to be coded in an XML data format that clearly delineates chapters and other information such as the book title, book author, chapter title, etc. Similar to text files, XML files can be opened and edited in any text editor. You can think of an XML file as being just like an HTML Web page file, except that you are dealing with a customized vocabulary (set of tags), as opposed to <html>, <p>, <div>, etc. XML files all have the file extension .xml.

Note

You often see the terms file and document used interchangeably in discussions about XML. Generally speaking, they mean the same thing. Where they do differ at times is when a chunk of XML code isn't necessarily related to a file on a hard disk. For example, it's entirely possible (and useful!) to generate XML code dynamically, in which case there is no concept of a file. In this situation, it makes more sense to refer to the XML code using the more abstract term document. I tend to follow this same terminology throughout the book.

So what kind of XML vocabulary do you use to represent an e-book? Although there are some standard e-book vocabularies out there, they tend to be fairly complicated and overkill for this example, so I thought it would be better to create our own. Rather than give you a play-by-play reference to what each tag means, just take a look at an excerpt from an actual book:

<?xml version="1.0" encoding="utf-8"?>
<ebook>
  <title>ALICE'S ADVENTURES IN WONDERLAND</title>
  <author>Lewis Carroll</author>
  <chapters>
    <chapter num="Chapter I" title="Down the Rabbit-Hole">
    Alice was beginning to get very tired of sitting by her
    sister on the bank, and of having nothing to do...
    </chapter>
    <chapter num="Chapter II" title="The Pool of Tears">
    &#39;Curiouser and curiouser!&#39; cried Alice (she was so
    much surprised, that for the moment she quite forgot how to
    speak...
    </chapter>
    ...
  </chapters>
</ebook>

The first line is admittedly a bit cryptic, and indicates that the XML code adheres to the XML 1.0 standard and uses a standard character encoding scheme (UTF-8); this is standard code that appears at the top of just about every XML document. The remainder of the code consists of e-book-specific code that should be fairly easy to understand given the tag and attribute names.

It works like this: The code for every e-book is sandwiched within an ebook element, which consists of opening and closing tags, like this:

<ebook>
  ...
</ebook>

Within the ebook element you place another container element (chapters) for the collection of chapters. Here's the e-book code after the chapters element is added:

<ebook>
  <chapters>
  ...
  </chapters>
</ebook>

Each chapter of an e-book is then coded using the <chapter> tag, which has two attributes for setting the chapter number and title: num and title. In addition to the two attributes, the <chapter> tag itself serves as a container for the chapter text. So, an individual chapter looks like this:

<chapter num="Chapter II" title="The Pool of Tears">
&#39;Curiouser and curiouser!&#39; cried Alice (she was so much
surprised, that for the moment she quite forgot how to speak...
</chapter>

The weird &#39; in the chapter text is an apostrophe (') that has been specially coded so as not to confuse the XML document processor. Another way to code such an element, also known as an entity in XML, is to use XML's standard apostrophe entity, which is &apos;. A similar coding is necessary for quote characters in e-books, in which case you use &#34; instead of the actual quote (").

Now that you understand the general structure of an e-book XML document and how to code each chapter of an e-book in XML, you can combine the two to make better sense of the code for an entire book. Here's the partial code for the book The War of the Worlds, by H. G. Wells:

Code View:
<?xml version="1.0" encoding="utf-8"?>
<ebook>
  <title>The War of the Worlds</title>
  <author>H. G. Wells</author>
  <chapters>
  <chapter num="" title="INTRO">
  But who shall dwell in these worlds if they be
  inhabited? .  .  .  Are we or they Lords of the
  World? .  .  .  And how are all things made for man?
  — KEPLER (quoted in The Anatomy of Melancholy)
  </chapter>
  <chapter num="BOOK ONE, CHAPTER ONE"
  title="THE EVE OF THE WAR">
  THE COMING OF THE MARTIANS

  No one would have believed in the last years of the
  nineteenth century that this world was being watched keenly
  and closely by intelligences greater than man&#39;s and yet
  as mortal as his own...
  </chapter>
  <chapter num="BOOK ONE, CHAPTER TWO"
  title="THE FALLING STAR">
  Then came the night of the first falling star. It was seen
  early in the morning, rushing over Winchester eastward, a
  line of flame high in the atmosphere. Hundreds must have
  seen it, and taken it for an ordinary falling star...
  </chapter>
  ...
 </chapters>
</ebook>

Hopefully the XML code is making a bit more sense now that you've seen parts of two different books coded using the same format. It's worth noting how The War of the Worlds is a bit unusual in that it is divided into two "books." Rather than modify the entire data format for what amounts to a different way to specify chapters, the book number is incorporated into the chapter number. Unlike some of the other e-books, this book is also interesting in that it takes advantage of both the chapter number and chapter title, which helps demonstrate the need for both pieces of information.

Although I have to admit it was no fun at all, I manually converted the five sample e-books from the previous chapter to the XML format you just learned about. It was no sweat until I encountered the beastly (literally!) Moby Dick, which is divided into 102 chapters! And don't even get me started on War and Peace, a novel of such epic proportions that it provides an excellent stress test for the Booker application. You'll ultimately find that coding e-books as XML is the most time-consuming part of customizing the Booker application to suit your own needs.

Earlier in the chapter I mentioned that XML files have .xml file extensions even though they are actually text files. Following are the sample e-books used in the updated Booker application, along with their respective filenames:

  • Alice's Adventures in Wonderland—book_alicewonderland.xml

  • Frankenstein—book_frankenstein.xml

  • Moby Dick—book_mobydick.xml

  • War and Peace—book_warandpeace.xml

  • The War of the Worlds—book_warofworlds.xml

The e-books are named using the same abbreviated titles as you saw before—the only change is that they have an .xml file extension instead of .txt. This means you can build an XML e-book filename programmatically using the following equation:

"book_" + AbbrevTitle + ".xml"

The next section reveals how the Booker application code uses this filename in conjunction with a chapter index to make Ajax requests to the server.

The Booker Web Page

Although there is a server-side component to the Booker application, the bulk of the work takes place on the client, which corresponds to the HTML Web page part of the application, booker.html. Figure 3.4 shows the newly revamped Booker application running in a Web browser, which reveals the updated user interface that provides buttons for chapter navigation.

Figure 3.4. Only a single e-book chapter is displayed now, and buttons are provided to navigate forward and back through other chapters.

[View full size image]

Note

If you're wondering where the Ajax diagnostic bar went in the Booker application, the answer is that I hid it so that it doesn't distract from the figures. In fact, the diagnostic bar doesn't appear in any of the remaining applications of the book. You can still easily enable the diagnostic bar in the examples by removing the style display:none from the Ajax state div (ID of ajaxState) in the HTML code for the Web page, or you can change the style to display:block if you want to leave the style so you can disable the bar later.

The figure reveals several new user interface facets to the application. First off, notice that the chapter title is displayed just below the e-book selection list. This area actually is capable of displaying both the chapter number and chapter title, but in the case of the introduction to The War of the Worlds only the chapter number (INTRO) appears.

Below the chapter heading (number + title) are two navigation buttons for moving to the first and previous chapters, respectively. Notice that these buttons are disabled in the figure, which is a subtle but handy user interface cue that you are viewing the first chapter of the book. The chapter text appears next, followed by additional navigation buttons for moving to the next and last chapters.

For testing purposes, I originally had all of the navigation buttons near each other above the chapter text, but it occurred to me that it wouldn't make much sense to read to the bottom of a chapter and then have to scroll up to navigate to the next chapter. That's why the Next and End (>>) buttons appear below the chapter text.

OK, I've beat around the bush long enough, so let's go ahead and take a look at the code for the body of the page, which establishes the user interface and wires together the scripted events:

Code View:
<body style="background:#EEEEEE"
  onload="document.getElementById('book').selectedIndex = 0;
  loadChapter(document.getElementById('book').options[
  document.getElementById('book').selectedIndex].value, 0)">
  <div id="ajaxState" style="display:none"></div>
  <br />
  <div style="margin-left:10%">Select book:
    <select id="book"
      onchange="loadChapter(this.options[
      this.selectedIndex].value, 0)">
      <option value="alicewonderland">Alice's Adventure's in
        Wonderland by Lewis Carroll</option>
      <option value="frankenstein">Frankenstein by Mary
        Shelley</option>
      <option value="mobydick">Moby Dick by Herman
        Melville</option>
      <option value="warandpeace">War and Peace by Leo
        Tolstoy</option>
      <option value="warofworlds">The War of the Worlds by
        H.G. Wells</option>
    </select>
  </div>
  <br />
  <div id="chapinfo" style="margin-left:10%; font-size:large">
  </div>
  <br />
  <div style="margin-left:10%">
    <input id="homeButton" type="button" value="<<"
      style="width:60px"
      onclick="curchapIndex = 1; prevChapter()" />
    <input id="prevButton" type="button"
      value="< Previous" style="width:120px"
      onclick="prevChapter()" />
  </div>
  <br />
  <div id="chaptext"
    style="margin-left:10%; margin-right:10%; padding:2%;
    background:#FFFFFF; border:thin solid #333333"></div>
  <br />
  <div style="margin-left:10%">
    <input id="nextButton" type="button" value="Next >"
      style="width:120px" onclick="nextChapter()"   />
    <input id="endButton" type="button" value=">>"
      style="width:60px"
      onclick="curchapIndex = (totalChapters - 2);
      nextChapter()" />
  </div>
</body>

Again, I realize this code is fairly JavaScript-laden for a book that claims you don't need to know anything about JavaScript. But keep in mind that the point is for you to be able to reuse this code in your own applications. And that is entirely possible without you necessarily understanding how every line of code works. Even so, it's worth painting a general picture of what is going on so that you have some insight into how you might make modifications. And don't forget that all of this code (and the remaining code in this section) is located in the booker.html file on the live Linux CD that accompanies the book.

First off, the user interface is organized into several div elements that provide a good means of cleanly organizing the chapter information and navigation buttons. Similar to the previous version of the application, a selection list containing the e-books is coded in HTML using the <select> tag. Of more interest in this version are the navigation buttons, which are coded using the <input> tag.

The functionality of the Previous and Next navigation buttons comes in the way of calls to the prevChapter() and nextChapter() JavaScript functions, which you see in a moment. The Home (<<) and End (>>) buttons use these same functions, but with the help of the curChapIndex variable, which keeps track of the current chapter index. You see how this variable works in a moment when you get into the JavaScript code for the application.

The other really important piece of code in the body of the Booker Web page is the code that loads an e-book based upon a selection change in the selection list:

loadChapter(this.options[this.selectedIndex].value, 0)

This code is identical to the selection-change code for the previous version of the application, except this code passes along the chapter index (0) in addition to the currently selected e-book (this.options[this.selectedIndex].value). The function name has also changed to loadChapter() from loadBook() to indicate that only a chapter is being loaded. A similar call to the loadChapter() function occurs in the onload event handler for the <body> tag, which is responsible for loading the first chapter of the first e-book in the list when the page is first opened.

Here's the code for the loadChapter() function, which loads a single chapter via an Ajax request given an abbreviated e-book title and chapter index:

function loadChapter(title, chapIndex) {
  // Could be a new book, so initialize the navigation buttons
  if (chapIndex == 0) {
    document.getElementById("homeButton").disabled = true;
    document.getElementById("prevButton").disabled = true;
    document.getElementById("nextButton").disabled = false;
    document.getElementById("endButton").disabled = false;
  }

  // Set the current chapter index
  curchapIndex = chapIndex;

  // Clear the previous chapter text
  replaceText(document.getElementById("chaptext"),
    "Loading...");

  // Send the Ajax request to load the new chapter
  var bookURL = "booker.php?title=" +
    encodeURIComponent(title) +
    "&chapIndex=" + encodeURIComponent(chapIndex);
  ajaxSendRequest("GET", bookURL, handleRequest);
}

The first several lines of the function initialize the navigation buttons so that they are enabled and disabled appropriately for the first chapter of the first book. The current chapter index is then stored away since you need to remember it in order to successfully navigate from one chapter to the next. The chapter text area serves double duty as a status notification for the loading of a chapter, and is set to "Loading..." while the chapter is being loaded. Once the chapter loads, this text is replaced with the actual chapter text. Finally, the actual Ajax request is sent via the GET request method by bundling the abbreviated title and chapter index into a URL. Notice that the familiar handleRequest() function is specified as the request handler, which means it gets called when the request completes.

The handleRequest() function does the lion's share of the work in the Booker application, which in this case consists of receiving the XML book data, plucking out the important information, and updating the elements on the page accordingly. Before exploring the code for this function, let's take a quick moment to recap the format of the XML data that is being sent back from the server in the Ajax response:

<bookData>
  <chapNum />
  <chapTitle>INTRO</chapTitle>
  <chapText>
  But who shall dwell in these worlds if they be
  inhabited? .  .  .  Are we or they Lords of the
  World? .  .  .  And how are all things made for man?
  — KEPLER (quoted in The Anatomy of Melancholy)
  </chapText>
  <totalChapters>28</totalChapters>
</bookData>

This is an example of the kind of XML data that must be processed by the handleRequest() function, whose code follows:

Code View:
function handleRequest() {
  if (request.readyState == 4 && request.status == 200) {
    // Store the XML response data
    var xmlData = request.responseXML.getElementsByTagName(
      "bookData")[0];

    // Store the total number of chapters
    totalChapters =
getText(xmlData.getElementsByTagName("totalChapters")[0]);

    // Display the chapter info
    var chapNum = getText(xmlData.getElementsByTagName(
      "chapNum")[0]);
    var chapTitle =
getText(xmlData.getElementsByTagName("chapTitle")[0]);
    var chapInfo;
    if (chapNum.length > 0 && chapTitle.length > 0)
      chapInfo = chapNum + " : " + chapTitle;
   else
     chapInfo = chapNum + chapTitle;
   replaceText(document.getElementById("chapinfo"), chapInfo);

   // Display the chapter text
   replaceText(document.getElementById("chaptext"),
     getText(xmlData.getElementsByTagName("chapText")[0]));
 }
 ajaxUpdateState();
}

The code first checks to make sure the Ajax request finished successfully, and then whittles down the XML data to the first bookData element, which in this case is the only bookData element. From there, JavaScript DOM functions are used to carefully extract each piece of data from the XML data. For example, the total number of chapters are grabbed and stored in the totalChapters variable with the following line of code:

totalChapters =
  getText(xmlData.getElementsByTagName("totalChapters")[0]);

If the total number of chapters happen to have been coded in XML with a different tag name (say, <NumberOfChapters>), then the previous line of code would simply be changed to this:

totalChapters =
  getText(xmlData.getElementsByTagName("NumberOfChapters")[0]);

This is an example of how you can modify the XML processing code of the application without necessarily digging into the nuts and bolts of the DOM functions that make it work.

Note

The getText() and replaceText() functions used in the Booker application are not standard JavaScript DOM functions but are instead part of the helper functions included with the book in the file domkit.js. The previous chapter explains the relevance of these functions and the other functions in the Ajax Toolkit.

The remainder of the code in the handleRequest() function involves plucking out pieces of information from the XML data and displaying them within each div element on the page. The code is smart enough to check for the presence of both a chapter number and chapter title, and combine them together if both exist. Otherwise, only the one that is specified is actually displayed. This is a clever way to account for the fact that some books have chapter numbers, some have chapter titles, and some have both.

The only part of the Web page you haven't seen are the two functions that respond to navigation button clicks, prevChapter() and nextChapter(). Let's start with the prevChapter() function, whose code follows:

function prevChapter() {
  if (curchapIndex > 0) {
    curchapIndex—;
    document.getElementById("nextButton").disabled = false;
    document.getElementById("endButton").disabled = false;
  }
  if (curchapIndex == 0) {
    document.getElementById("homeButton").disabled = true;
    document.getElementById("prevButton").disabled = true;
  }
  loadChapter(document.getElementById('book').options[
    document.getElementById('book').selectedIndex].value,
      curchapIndex);
}

A majority of the code in this function is devoted to intelligently enabling and disabling the navigation buttons based upon whether or not the current chapter is the first chapter. Once the navigation button logic is carried out, the loadChapter() function is called with the current chapter index used to specify which chapter to load.

The nextChapter() function is very similar to prevChapter(), with the role reversed to focus on the last chapter instead of the first. In other words, if the current chapter is the last chapter, then it is important for the nextChapter() function to disable the Next button. The following code shows how the totalChapters variable is used as the basis for determining if the current chapter is the last chapter:

function nextChapter() {
  if (curchapIndex  < (totalChapters - 1)) {
    curchapIndex++;
    document.getElementById("homeButton").disabled = false;
    document.getElementById("prevButton").disabled = false;
  }
  if (curchapIndex == (totalChapters - 1)) {
    document.getElementById("nextButton").disabled = true;
    document.getElementById("endButton").disabled = true;
  }
  loadChapter(document.getElementById('book').options[
    document.getElementById('book').selectedIndex].value,
      curchapIndex);
}

This wraps up the client side of the newly revamped Booker application. All that's left is a quick look at the server script, which is a piece of cake compared to the client.

The Booker Server Script

The PHP script on the server side of the Booker application is responsible for reading an entire e-book XML file and then dynamically generating an XML document containing only the relevant chapter information needed by the Web page. This chapter information is relayed back to the client via an Ajax response. Following is the code for the server PHP script, booker.php:

<?php
header('Content-Type: text/xml');

// Parse the e-book XML data into a structure
$rawBook = file_get_contents("book_" . $_REQUEST['title'] .
  ".xml");
$xml = new SimpleXmlElement($rawBook);

$chap = $xml->chapters->chapter[intval($_REQUEST['chapIndex'])];
$xmlChapter = '<?xml version="1.0" encoding="utf-8"?>';
$xmlChapter .= '<bookData>';
$xmlChapter .= '<chapNum>' . $chap['num'] . '</chapNum>';
$xmlChapter .= '<chapTitle>' . $chap['title'] . '</chapTitle>';
$xmlChapter .= '<chapText>' . $chap . '</chapText>';
$count = 0;
foreach ($xml->chapters->chapter as $chapter) {
  $count++;
}
$xmlChapter .= '<totalChapters>' . $count . '</totalChapters>';
$xmlChapter .= '</bookData>';

// Generate a book info XML document
echo $xmlChapter;
?>

Granted, if you don't know anything about PHP, then this code likely looks very foreign. Rather than trying to teach you a new language, which is certainly beyond the scope and realm of this book, I'll serve as an interpreter. The beginning of the code establishes that the data being returned is in the XML data format; this is critical so that the server packages up the code properly when delivering the data back to the client in the Ajax response.

The first big chunk of code in the script is responsible for reading an entire e-book from an XML file into a data structure that can be further processed. The piece of code $_REQUEST['title'] is where the PHP script is gaining access to the title parameter that was sent along in the URL of the Ajax request. Remember this code:

booker.php?title=warofworlds&chapIndex=0

The code $_REQUEST['title'] is grabbing the title value sent along in this URL. Similarly, to grab the value of the chapIndex parameter, you use this piece of code:

$_REQUEST['chapIndex']

Getting back to the part of the script that parses in the XML e-book, the code builds a file name, such as book_warofworlds.xml, and reads it into an XML data structure. From there, the main big chunk of code kicks in and rips into the XML code looking for the specified chapter, as indicated by the chapIndex parameter to the script. This code is effectively reading and writing XML at the same time—it is plodding through the entire e-book looking for specific chapter information, and then writing a new XML document containing that information. The end result is the concise XML response data with the <bookData> tag you saw in the previous section.

To really get a sense for how the server script works, it's best to open one of the e-book XML files in a text editor and study the tags as you go line by line through the last big chunk of code in the script. You'll start to see a pattern where each tag and attribute is methodically drilled into and its relevant data extracted and packaged into a new XML tag.

When all is said and done with the script building a new XML document of chapter information, the data is returned to the client with a single line of code:

echo $xmlChapter;

I know that's kind of anticlimactic for how much work the script is doing, but that's how PHP can be. The real climax is yet to come in the next section when you take the application for a spin around the block. Before you get to that, however, let's take a quick look at how you can go about testing a PHP script.

You know that the Ajax request for the Booker application consists of a URL that passes parameters to a PHP script. You also know that the script is responsible for sending back an XML document as the response to that request. It can be very helpful to study that response outside of the context of the Ajax request, meaning that you're taking a peek at what the PHP script generates directly in a Web browser. You do this simply by entering the URL of the Ajax request as the address of a Web page in your browser, like this:

http://www.yourdomain.com/booker.php?title=warofworlds&chapIndex=0

Assuming the PHP script and XML e-books are stored on your server, change the domain to match yours in this line of code and then enter the URL into your Web browser. You can also try this trick directly on the live Linux CD that accompanies this book. Either way, Figure 3.5 shows the XML response data generated by the PHP script.

Figure 3.5. Opening a PHP script directly in a browser gives you a handy means of finding out exactly what kind of response it is generating.

[View full size image]

Keep this little trick in mind as you work through other examples in the book, as well as projects of your own. I used it quite often while developing the sample applications, and several times it illuminated an error in the PHP script that wouldn't have surfaced otherwise.


ch03lev1sec4.html

Testing Booker

With all the hard work behind you, the testing phase is the fun part of the process. Figure 3.6 shows the new Booker application with the book War and Peace open to its first chapter. To follow along in your own browser, open the booker.html page in the chap03 example code folder on the accompanying live Linux CD.

Figure 3.6. The new Booker application starts out by loading the first chapter of the selected book.

[View full size image]

Note

At some point you want to consider exploring server logs as a means of finding out exactly what is taking place in regard to Ajax requests. You'll need to check the documentation for your specific Web server, but all Web servers include logs so that you can find out what requests are made and if something went wrong. You can also view similar information specifically related to Ajax requests directly in your Web browser by using a JavaScript debugger such as Firebug.

Notice in the figure that the chapter number and title appear just below the selection list, which helps give the page a bit more of the feel of a real book. Below that are the Home and Previous navigation buttons, which are initially disabled because it's impossible to move backward from the first chapter in the book.

If you scroll on down to the bottom of the chapter you'll see the other pair of navigation buttons, shown in Figure 3.7, which allow you to either move to the next chapter or jump straight to the last chapter in the book.

Figure 3.7. The Next and End navigation buttons appear at the bottom of a chapter, and allow you to navigate forward in the e-book.

[View full size image]

Clicking the Next button takes you to the next chapter, as shown in Figure 3.8.

Figure 3.8. Moving to a new chapter causes the chapter heading to update, as well as the chapter text.

[View full size image]

This figure now shows the Home and Previous buttons enabled since you are no longer on the first chapter.

As with the earlier version of the application, you can select other books from the selection list and they will load via Ajax. The difference now is that every e-book is handled on a chapter-by-chapter basis, which is a significant improvement both in terms of readability and performance.


ch03lev1sec5.html

Giving Booker an Extreme Ajax Makeover

It's fairly easy to see how the new Booker e-book viewer could be a handy tool for serving up e-books online. But assuming you aren't in the business of opening a virtual Web library, what else could the application possibly be altered to accomplish. Keep in mind that the application excels at processing any text document that benefits from being broken into discrete parts. In the case of an e-book, those parts are chapters, but they could really be anything.

One potential twist on the Booker application is a data-driven blog tool. For example, you could alter the existing application so that each "book" corresponds to a blog topic, such as Business, Sports, or Politics. Then within each topic the "chapters" become individual blog entries. The cool thing about this repurposing of Booker is that you could pull it off with literally no changes to the JavaScript or PHP code. You'd need to make a few minor HTML changes to the selection list so that it displays blog topics instead of books, but other than that all of the changes take place in the XML files, which is a good thing.

Remember that the XML file for each e-book includes three primary pieces of information for a given chapter: number, title, and text. The only piece of information that doesn't really fit the blog idea is the chapter number, which could easily be repurposed as the blog date/time. So it's possible to code a blog document exactly like one of the e-books but with the blog date and time specified as the chapter number, the blog title as the chapter title, and the blog text as the chapter text. Here's an example of what such a document might look like:

<?xml version="1.0" encoding="utf-8"?>
<ebook>
  <title>Michael's Sports Blog</title>
  <author>Michael Morrison</author>
  <chapters>
    <chapter num="01/16/2007 8:00pm"
    title="Predators Have Most Wins">
    After last night&#39;s win against conference rival Calgary,
    the Nashville Predators are now the first team to reach 32
    wins in the NHL this season, and are only one point behind
    Anaheim in the entire league. Go Preds!
    </chapter>
    <chapter num="12/31/2006 11:30pm"
    title="Titans Eliminate Themselves">
    In a loss that will haunt the franchise until next season,
    the Tennessee Titans&#39; miraculous season turn-around came
    to a screeching halt as they lost to the Patriots in Week 17
    and eliminated themselves from the playoffs.
    </chapter>
  </chapters>
</ebook>

Granted, you could argue that the XML vocabulary should be modified so that the blog XML code doesn't have tags such as <ebook> and <chapter>, but that's not really critical. If you feel comfortable enough to tinker with the XML vocabulary, by all means do so. But short of that, you can accomplish quite a lot by simply altering the content of the XML files.


ch03lev1sec6.html

Summary

You're only three chapters in and you now have an Ajax-powered e-book viewer that is capable of dynamically loading individual chapters from e-books that are coded using a custom XML language. Sounds like a lot of complexity, but hopefully you realized that there wasn't an enormous amount of code involved in an application that's doing quite a lot. I'm not saying the code is easy to digest the first time around, but it is fairly concise. More importantly, you learned that the code is quite extensible, allowing you to transform the application into something else entirely with surprisingly few changes.


ch04.html

Chapter 4. Using Ajax to Dynamically Populate Lists: A Stock Picker

Covert Ajax

Who would've thought that Ajax has a connection to conflict in the Middle East? In 1953 the United Kingdom and United States collaborated in a covert operation to overthrow Iranian Prime Minister Mohammed Mossadegh. Operation Ajax was a short-term success but did little to stabilize relations between Iran and the West, as the 1979 Islamic Revolution and events thereafter have proved.

A fairly common user interface design in Web pages is to use multiple selection lists to allow users to pick hierarchical data. A good example is a city/state/country selection, where a list of countries in one list determines which states can be selected in another list, which in turn determines which cities can be selected in a third list. The idea is to constrain a user's possible choices in one list based upon the selection in another. Although this feature can certainly be created using nothing more than client-side JavaScript code, Ajax is necessary in order to dynamically build the selection lists from data obtained from a server.

This chapter explores this problem in detail and shows you exactly how to use Ajax to dynamically build selection lists from server data. This is a handy Ajax design pattern you are likely to want to repeat in your own applications. What's more, in the process of developing another practical sample application, you add a few more Ajax tricks to your rapidly expanding repertoire.

The following files are used by the Picker application in this chapter, and are located on the live Linux CD-ROM with the book in the chap04 example code folder:

  • picker.html—Main Web page

  • quoter.php—Server script for loading a stock quote

  • ajaxkit.js—Core Ajax functions for the Ajax Toolkit

  • domkit.js—DOM-related functions for the Ajax Toolkit

  • stocks.xml—XML list of stock picks

The Challenge: Displaying Selected Stock Information

The challenge is simple: Use Ajax to dynamically populate a selection list based upon a choice made in another selection list. Why bother? Because in plenty of scenarios such a two-pronged selection approach makes a lot of sense. In fact, a four-pronged approach is used thousands of times a day on one of the most popular Web sites known to man. I'm talking about eBay—specifically the category selection part of listing an item for auction. Figure 4.1 shows how eBay uses up to four selection lists to allow the user to drill down into subcategories when listing an item.

Figure 4.1. eBay is a perfect example of using multiple selection lists to allow the user to make selections between interdependent data.

[View full size image]

Such an arrangement of selection lists provides the user an intuitive way to make a selection when dealing with data that is in some way hierarchical. If you can think of a set of data as a sequence of decisions or can somehow organize it into a tree-like structure that fans out (think of a family tree), then you may have a good opportunity to use two or more dynamically populated selection lists.

It's worth clarifying that you don't need Ajax to create selection lists that allow the user to navigate hierarchical data. You see the country/state/city example used all over the place without any Ajax help at all. It's entirely possible to hard-code such data directly in the JavaScript code of a Web page. The problem is, you have to edit the Web page every time you want to update the selection options, and in some cases this simply isn't possible. One key concept behind Ajax applications is to make the user interface data-driven, which in this case means building the selection list dynamically from data obtained from the server.

Note

If you do any other Ajax reading, you will eventually come across an Ajax selection list example that uses the familiar country/state/city data. Although the data itself is perfect for a hierarchical selection user interface, it's not necessarily good from an Ajax perspective because countries, states, and cities rarely change. It's not as if Alabama gets shuffled into another country every few years. For this reason, I don't see the point in using a data-driven programming technique on static data unless the goal is to simply make the application more maintainable, which is an admirable goal. I've tried hard to make the examples in this book count, and the selection list example in this chapter is no different.

If you think about the data-driven nature of the multiple selection list technique, there are many applications where it could be used. A company directory that is navigable according to departments or security classifications is one possibility. Another is a product catalog organized by department, as in clothing, hardware, etc. One application that grabbed my attention is that of an investment service that offers advice in the form of a list of hot, cold, and safe stocks. It's not that I necessarily am itching to use such a service, but it provides an opportunity to use Ajax on two fronts:

  • Dynamically populating a selection list

  • Retrieving a real-time stock quote

The first task is the real focus of this chapter, whereas the second task is a fringe benefit of creating an application that has a practical need that can be met by Ajax.

The application you develop in this chapter is called Picker, as in stock picker, and it presents two selection lists—one with stock types and the other with actual stocks. Stock types include hot, cold, and safe. The stock list is dynamically populated based upon selections made in the stock type list. An editor of such a site could make back-end changes to the stock picks on the server with the results automatically carrying over to the data-driven page. The stock quote enters the picture when a stock has been selected in the stock list. Detailed information, including the current stock price, is displayed below the two selection lists.

What you really have in this application is two trickle-down Ajax requests:

  • The first Ajax request grabs a list of stocks from the server based upon the selected stock type (hot, cold, or safe).

  • The second Ajax request grabs the latest information about a specific stock based upon the selected stock in the stock list.

If this sounds like a bold challenge, don't sweat it too much because Ajax provides a clear path to accomplishing these tasks without too much trouble. The trick is coming up with a simple design so that the code doesn't get out of hand.


ch04lev1sec1.html

Chapter 4. Using Ajax to Dynamically Populate Lists: A Stock Picker

Covert Ajax

Who would've thought that Ajax has a connection to conflict in the Middle East? In 1953 the United Kingdom and United States collaborated in a covert operation to overthrow Iranian Prime Minister Mohammed Mossadegh. Operation Ajax was a short-term success but did little to stabilize relations between Iran and the West, as the 1979 Islamic Revolution and events thereafter have proved.

A fairly common user interface design in Web pages is to use multiple selection lists to allow users to pick hierarchical data. A good example is a city/state/country selection, where a list of countries in one list determines which states can be selected in another list, which in turn determines which cities can be selected in a third list. The idea is to constrain a user's possible choices in one list based upon the selection in another. Although this feature can certainly be created using nothing more than client-side JavaScript code, Ajax is necessary in order to dynamically build the selection lists from data obtained from a server.

This chapter explores this problem in detail and shows you exactly how to use Ajax to dynamically build selection lists from server data. This is a handy Ajax design pattern you are likely to want to repeat in your own applications. What's more, in the process of developing another practical sample application, you add a few more Ajax tricks to your rapidly expanding repertoire.

The following files are used by the Picker application in this chapter, and are located on the live Linux CD-ROM with the book in the chap04 example code folder:

  • picker.html—Main Web page

  • quoter.php—Server script for loading a stock quote

  • ajaxkit.js—Core Ajax functions for the Ajax Toolkit

  • domkit.js—DOM-related functions for the Ajax Toolkit

  • stocks.xml—XML list of stock picks

The Challenge: Displaying Selected Stock Information

The challenge is simple: Use Ajax to dynamically populate a selection list based upon a choice made in another selection list. Why bother? Because in plenty of scenarios such a two-pronged selection approach makes a lot of sense. In fact, a four-pronged approach is used thousands of times a day on one of the most popular Web sites known to man. I'm talking about eBay—specifically the category selection part of listing an item for auction. Figure 4.1 shows how eBay uses up to four selection lists to allow the user to drill down into subcategories when listing an item.

Figure 4.1. eBay is a perfect example of using multiple selection lists to allow the user to make selections between interdependent data.

[View full size image]

Such an arrangement of selection lists provides the user an intuitive way to make a selection when dealing with data that is in some way hierarchical. If you can think of a set of data as a sequence of decisions or can somehow organize it into a tree-like structure that fans out (think of a family tree), then you may have a good opportunity to use two or more dynamically populated selection lists.

It's worth clarifying that you don't need Ajax to create selection lists that allow the user to navigate hierarchical data. You see the country/state/city example used all over the place without any Ajax help at all. It's entirely possible to hard-code such data directly in the JavaScript code of a Web page. The problem is, you have to edit the Web page every time you want to update the selection options, and in some cases this simply isn't possible. One key concept behind Ajax applications is to make the user interface data-driven, which in this case means building the selection list dynamically from data obtained from the server.

Note

If you do any other Ajax reading, you will eventually come across an Ajax selection list example that uses the familiar country/state/city data. Although the data itself is perfect for a hierarchical selection user interface, it's not necessarily good from an Ajax perspective because countries, states, and cities rarely change. It's not as if Alabama gets shuffled into another country every few years. For this reason, I don't see the point in using a data-driven programming technique on static data unless the goal is to simply make the application more maintainable, which is an admirable goal. I've tried hard to make the examples in this book count, and the selection list example in this chapter is no different.

If you think about the data-driven nature of the multiple selection list technique, there are many applications where it could be used. A company directory that is navigable according to departments or security classifications is one possibility. Another is a product catalog organized by department, as in clothing, hardware, etc. One application that grabbed my attention is that of an investment service that offers advice in the form of a list of hot, cold, and safe stocks. It's not that I necessarily am itching to use such a service, but it provides an opportunity to use Ajax on two fronts:

  • Dynamically populating a selection list

  • Retrieving a real-time stock quote

The first task is the real focus of this chapter, whereas the second task is a fringe benefit of creating an application that has a practical need that can be met by Ajax.

The application you develop in this chapter is called Picker, as in stock picker, and it presents two selection lists—one with stock types and the other with actual stocks. Stock types include hot, cold, and safe. The stock list is dynamically populated based upon selections made in the stock type list. An editor of such a site could make back-end changes to the stock picks on the server with the results automatically carrying over to the data-driven page. The stock quote enters the picture when a stock has been selected in the stock list. Detailed information, including the current stock price, is displayed below the two selection lists.

What you really have in this application is two trickle-down Ajax requests:

  • The first Ajax request grabs a list of stocks from the server based upon the selected stock type (hot, cold, or safe).

  • The second Ajax request grabs the latest information about a specific stock based upon the selected stock in the stock list.

If this sounds like a bold challenge, don't sweat it too much because Ajax provides a clear path to accomplishing these tasks without too much trouble. The trick is coming up with a simple design so that the code doesn't get out of hand.


ch04lev1sec2.html

The Design: Designing a Stock Picker

The design of any Ajax application in large part boils down to a careful analysis of what data is being shuttled between the client and server. In the case of the Picker application, two different Ajax requests are taking place, one after the next, so you have double the design work. Fortunately, neither request is particularly complex, so the design can still remain straightforward.

The first request is in response to the user selecting a stock type from the first selection list. When this type is selected, a request is made that hits the server for a list of stocks matching that particular type. At this point all you're trying to do is get a list of stocks based on a selected type. This list of stocks is used to populate the second selection list, which just so happens to serve as the basis for the second Ajax request.

The second request is initiated when the user chooses a stock from the second selection list, the stock list. This request performs a live lookup of stock information from a Web service that provides financial data. Unless you happen to run a financial stock quote server, this is a request you'll be making to a third-party service, as opposed to serving up your own data as in the first request. The up-to-the-minute stock information returned by the server is then displayed on the Web page. Figure 4.2 shows a crude representation of how the user interface of the application translates into Ajax requests.

Figure 4.2. The user interface for the Picker application consists of two selection lists and a text area containing information about the selected stock.

Now that you have an idea of the general design of the Picker application, let's look a bit closer at the specific Ajax requests and responses, and what kind of data is flying around in them.

The Client Requests

The data sent from the client to the server in the Picker application is extremely minimal. In fact, for the initial stock list request, nothing at all needs to be sent because the XML data for the stock list is small enough that it's not a problem just to retrieve the entire document and parse out what you need directly in client-side JavaScript code. So, you don't have to worry about sending anything along with the first request.

The second request obviously has to send at least the name of a stock because it is performing a stock lookup on a financial server. It's pretty surprising how much information you can get just from the ticker symbol of a stock. For this reason, all you have to send with the second request is the stock symbol, which is typically a three-or four-letter word such as SBUX (Starbucks), FDX (FedEx), AMZN (Amazon), etc.

That wraps up the rather simplistic data sent from the client to the server. Let's now address what the server sends back.

The Server Responses

The first Ajax request made to the server is to retrieve the entire list of stocks, regardless of the stock type selected. You could argue that this request should include the stock type and therefore only return stocks of a single type in the response, but the role of the server is simplified if you just grab the entire list of stocks. In fact, you don't need a server script at all to request an entire XML document.

The XML document returned by the server in the stock list response is a list of stocks for all of the possible stock types. The responsibility then falls on the Web page to process the list and pluck out stocks of a given type in order to fill the second selection list. You see an example of the specific XML data for the stocks in the next section.

The second Ajax request prompts the server to return information about a particular stock, including the latest stock price. Because this information is obtained from a third-party service (in this case, webserviceX.net), the stock information returned by the server is not something directly within your control. Not only that, but there is a problem inherent in trying to use Ajax to request data from a server other than your own—it isn't allowed! For security purposes, you aren't allowed to carry out an Ajax request with a server at a domain other than where the request originates. What to do?

Although there are other ways around the Ajax security restriction, we'll use a PHP script as a proxy for snagging data from the third-party server. It works like this: Your Ajax client makes a request to a PHP script on your server, which in turn grabs the data from the third-party server. This is allowed because server-to-server communication isn't restricted in the same way as client-to-server communication. And as you learn a bit later in the chapter, the PHP script required to pull this off is literally only a few lines of code.

So getting back to the overall server-response picture of the Picker application, the entire list of stocks is returned in the first Ajax response, which is triggered when the user selects a stock type from the first selection list. The second request, which is initiated by a stock selection from the second selection list, results in a response that contains detailed stock information, including the current price. The second response is indirectly received from a third-party Web service, webserviceX.net, that offers several handy data feeds in XML format.

Making Sense of the Client-to-Server Conversation

You now have enough of the data communication equation for the Picker application to put everything together into one cohesive design that factors in what is being sent and received in each of the two Ajax requests. Figure 4.3 shows the client-to-server conversation taking place with respect to these requests.

Figure 4.3. The Picker application involves data flowing back and forth in two different Ajax requests.

The figure reveals how the two Ajax requests generate responses that relay the stock list and stock information back to the browser (client), respectively. The first request sends no extra data along to the server, whereas the second request sends only the ticker symbol of the stock in question. This symbol is packaged into a URL as a single parameter. Here's an example of a URL used to pass along a stock symbol to the PHP script for the Picker application:

quoter.php?symbol=EBAY

This code reveals that the PHP script responsible for handling the second Ajax request is in the file named quoter.php. You learn how this script works a bit later in the chapter. For now, let's go back to the first Ajax request and the type of data it expects in return from the server.

The first Ajax request expects an XML document back from the server that contains the entire list of stocks used by the application, including all of the stock types. Following is an example of what this XML code looks like:

<stocks>
  <hot>
    <stock>AAPL</stock>
    <stock>LUV</stock>
    ...
  </hot>
  <cold>
    <stock>HSY</stock>
    <stock>WIN</stock>
    ...
  </cold>
  <safe>
    <stock>KO</stock>
    <stock>CAT</stock>
    ...
  </safe>
</stocks>

As you can see, the stocks are organized into groups that are defined by tags such as <hot>, <cold>, and <safe>. Within each of these groups of tags for each stock type you find the individual stocks, which are coded using the <stock> tag. It's important to note that ticker symbols are used to identify the stocks, as opposed to actual company names. This is a critical design decision because the ticker symbol of a stock is what is used to look up any given stock, and can be thought of as a unique identifier for the stock.

In the actual data file for the stock list, I included five stocks for each of the different stock types, but you are free to include however many you want. As you see later in the chapter, the Picker application reads all of the stocks within a given type and adds them to the second selection list, so there isn't really a hard limit on how many stocks you include in the stock list XML data.

Perhaps of more interest is the XML data returned by the server in response to the second Ajax request. This response data consists of detailed stock information, and is generated by the third-party Web service webserviceX.net. Following is an example of the kind of XML data generated by a stock quote request sent to webserviceX.net:

Code View:
<string>
  <StockQuotes>
    <Stock>
      <Symbol>GOOG</Symbol>
      <Last>504.28</Last>
      <Date>1/16/2007</Date>
      <Time>4:00pm</Time>
      <Change>-0.72</Change>
      <Open>507.87</Open>
      <High>513.00</High>
      <Low>503.30</Low>
      <Volume>7579201</Volume>
      <MktCap>154.4B</MktCap>
      <PreviousClose>505.00</PreviousClose>
      <PercentageChange>-0.14%</PercentageChange>
      <AnnRange>331.55 - 513.00</AnnRange>
      <Earns>7.875</Earns>
      <P-E>64.13</P-E>
      <Name>GOOGLE</Name>
    </Stock>
  </StockQuotes>
</string>

The stock information is probably a bit more detailed than you were expecting, and it certainly contains more information than the Picker application really needs. However, because the data is there, you might as well use as much of it as possible. More specifically, the Picker application ends up using the following pieces of data from the stock information returned in the Ajax response:

  • Stock name (<Name>)

  • Latest price quote (<Last>)

  • Market capitalization (<MktCap>)

  • Trading volume (<Volume>)

  • Percent change in price (<PercentageChange>)

  • Price-to-earnings ratio (<P-E>)

  • Date and time of price quote (<Date> and <Time>)

This is all information a prospective investor might want to know about a particular stock being recommended. Now you just need to figure out how to incorporate all this data into the application itself.


ch04lev1sec3.html

Putting Together the Stock Picker

Like many of the sample Ajax applications throughout the book, the Picker application involves three primary components:

  • XML file (stocks.xml)

  • HTML Web page (picker.html)

  • PHP server script (quoter.php)

In addition to these three parts of the application, a third-party financial Web service is responsible for providing the live stock data. Although this service is an important part of the application, it doesn't require a distinct component other than code within the HTML Web page that initiates an Ajax request and code within the PHP server script that handles relaying the response back to the page. This arrangement is necessary because Ajax requests aren't allowed direct access to resources located on other domains.

Let's break down each part of the Picker application in more detail so you can fully understand how the application works.

The Stocks XML File

The stocks XML file is entirely generated by you, and is responsible for controlling the stocks displayed in the application based upon the stock type selected. Following is the complete code for the sample stocks.xml file, which contains a list of more or less random stock picks:

Code View:
<?xml version="1.0" encoding="utf-8"?>
<stocks>
  <hot>
    <stock>AAPL</stock>
    <stock>LUV</stock>
    <stock>GOOG</stock>
    <stock>FDX</stock>
    <stock>TM</stock>
  </hot>
  <cold>
    <stock>HSY</stock>
    <stock>WIN</stock>
    <stock>MRK</stock>
    <stock>AMGN</stock>
    <stock>BBY</stock>
  </cold>
  <safe>
    <stock>KO</stock>
    <stock>CAT</stock>
    <stock>DIS</stock>
    <stock>GE</stock>
    <stock>MSFT</stock>
  </safe>
</stocks>

Note

I strongly encourage you not to bet the farm on these stock picks! The designation of stocks as being hot, cold, or safe is random for the most part, so don't hold me to it if you put your nest egg in Apple (AAPL) stock and the iPhone ends up being a flop.

You saw an excerpt of this code earlier in the chapter, so it shouldn't be entirely foreign to you at this point. Keep in mind that this entire XML file is sent back to the client as the response to the first Ajax request, which is initiated by a stock type selection in the first selection list.

Tip

The stocks.xml file uses stock ticker symbols instead of company names to designate stocks. When assembling your own list of stocks, you may need to find their ticker symbols. You can use an online tool such as Yahoo!'s Symbol Lookup (http://finance.yahoo.com/lookup) to determine such ticker symbols. Also keep in mind that the Picker application will work fine for mutual funds, exchange traded funds (ETFs), and just about anything that has a ticker symbol associated with a major financial exchange; you aren't limited solely to stocks.

Each individual stock is coded using the <stock> tag with no attributes, and the <stock> tags are carefully arranged within tags that indicate their type. For example, to designate a stock as being "hot," you simply place its <stock> tag in between the <hot> and </hot> tags. You can include as many stocks as you want within each stock type—the client JavaScript code automatically fills the stock selection list with every stock listed for a given type.

The Picker Web Page

The HTML Web page for the Picker application (picker.html) is relatively simple in terms of its user interface, consisting primarily of two selection lists and a few div and span elements for holding the detailed stock information. Figure 4.4 shows the Picker application open in a Web browser with both selection lists and the stock information in view.

Figure 4.4. The Picker Web page consists of two selection lists and an area for displaying the stock information.

[View full size image]

With this figure in mind, check out the HTML code for the body of the page:

Code View:
<body onload="document.getElementById(
  'stocktype').selectedIndex = 0; loadStockList()">
  <div id="ajaxState" style="display:none"></div>
  <br />
  <div>Select type:
    <select id="stocktype" onchange="loadStockList()">
      <option value="hot">Hot Stocks</option>
      <option value="cold">Cold Stocks</option>
      <option value="safe">Safe Stocks</option>
    </select>
  </div>
  <br />
  <div>Select stock:
    <select id="stock"
onchange="loadStockInfo(this[this.selectedIndex].value);">
    </select>
  </div>
  <br />
  <div id="stockname" style="font-size:large; font-weight:bold">
  </div>
  Share price:  <span id="stockprice" style="font-weight:bold">
  </span><br />
  Market cap:  <span id="stockcap" style="font-weight:bold">
  </span><br />
  Trading volume:  <span id="stockvolume"
  style="font-weight:bold"></span><br />
  % change:  <span id="stockchange" style="font-weight:bold">
  </span><br />
  P/E ratio:  <span id="stockpe" style="font-weight:bold">
  </span><br />
  <div id="stockdatetime" style="font-style:italic"></div>
</body>

The first selection list (stocktype) is coded with fixed options for the different stock types. These stock types are used as the basis for dynamically filling the second selection list (stock), which starts out empty.

The last section of the page contains a couple div elements and several span elements used to cleanly format the stock information. A careful examination of the code reveals how each piece of information is preceded by a label, and in some cases a formatting character such as a dollar sign ($) to help show that the data is monetary. The stock name and date/time are the only elements without labels because the stock name element serves double duty as a status notification for the Ajax request. More specifically, the stock name element displays the text "Loading..." while a stock is being loaded. This lets the user know that a request for data has been made. The meaning of the date/time element on the page should be fairly obvious to the user, so no label is used there either.

The only JavaScript code in the body of the page is located in the onload event handler for the <body> tag and the onchange event handlers for the selection lists. The onload code takes care of initially setting the first stock type as the first selection, and then loading the stock list based upon that selection. This latter step is accomplished by calling the loadStockList() function, which you see in just a moment. For now, just know that this function initiates the Ajax request for loading the stock list from the server.

The loadStockList() function is also called any time the user chooses a different stock type in the first selection list. This action is what triggers the onchange event, resulting in the call to loadStockList(). A similar thing occurs when a change takes place in the second list, except this time the loadStockInfo() function is called to initiate the Ajax request for loading information about an individual stock. The currently selected stock is passed as the only argument into this function.

The loadStockList() function does nothing more than send an Ajax request to grab the contents of the stocks.xml file:

function loadStockList() {
  // Send the Ajax request to load the new stock list
  ajaxSendRequest("GET", "stocks.xml", handleStockListRequest);
}

The key thing to notice in this code is the name of the request handler, which is handleStockListRequest(). This function is responsible for handling the Ajax request upon completion. Here's the code for it:

Code View:
function handleStockListRequest() {
  if (request.readyState == 4 && request.status == 200) {
    // Store the XML response data
    var xmlData = request.responseXML.getElementsByTagName(
      "stocks")[0];

    // Isolate the data for the current stock type
    var listData = xmlData.getElementsByTagName(
      document.getElementById('stocktype').options[
      document.getElementById('stocktype').selectedIndex].
      value);

    // Clear the stock list
    var stockSel = document.getElementById('stock');
    while (stockSel.length > 0)
      stockSel.remove(0);

    // Fill the stock list with stock symbols
    for (var i = 0; i  < listData[0].childNodes.length; i++) {
      if (listData[0].childNodes[i].nodeType == 1) {
        var symbol = getText(listData[0].childNodes[i]);
        stockSel.add(new Option(symbol, symbol, false, false),
          null);
      }
    }

    // Select the first stock in the list
    stockSel.selectedIndex = 0;

    // Load the info for the first stock in the list
    loadStockInfo(stockSel[0].value);
  }
  ajaxUpdateState();
}

I realize this is a fairly hefty function, but it's really not all that complicated in terms of what it's actually doing. Refer back to the stocks.xml file to understand what kind of data this function is processing. The objective of the function is to drill down into the stocks.xml data and grab the list of stocks associated with a given stock type (hot, cold, or safe). More specifically, this list of stocks appears within a given stock type tag (<hot>, <cold>, or <safe>).

After initially retrieving the XML data from the server, the handleStockListRequest() function whittles down the XML data to a particular stock type. As an example, the subset of XML data for hot stocks looks like this:

<hot>
  <stock>AAPL</stock>
  <stock>LUV</stock>
  <stock>GOOG</stock>
  <stock>FDX</stock>
  <stock>TM</stock>
</hot>

Now the code is just about ready to cycle through the list of stocks within the <hot> tag to fill the selection list with hot stocks. Before it can do so, however, the list must be cleared to ensure that the previously displayed stocks are gone. After the stock list is cleared, it is then filled with stocks in the remaining XML data. For this example, this means that five stocks are added to the stock selection list. After the stock list is filled, the selection is set to the first stock in the new list.

This is where things get kind of interesting, because you've filled the stock list dynamically but you don't yet have any stock information to display. You need to display information for the first stock in the new list. This is accomplished by the call to the loadStockInfo() function, which accepts the value of the first stock as its only argument. This function call results in the initiation of the second Ajax request, whose job is to get information for a specified stock.

Following is the code for the loadStockInfo() function:

function loadStockInfo(stock) {
  // Clear the previous stock info text
  replaceText(document.getElementById("stockname"),
    "Loading...");
  replaceText(document.getElementById("stockprice"), "");
  replaceText(document.getElementById("stockcap"), "");
  replaceText(document.getElementById("stockvolume"), "");
  replaceText(document.getElementById("stockchange"), "");
  document.getElementById("stockchange").style.color = "#000000";
  replaceText(document.getElementById("stockpe"), "");
  replaceText(document.getElementById("stockdatetime"), "");

  // Send the Ajax request to load the new stock info
  ajaxSendRequest("GET", "quoter.php?symbol=" +
    encodeURIComponent(stock), handleStockInfoRequest);
}

Other than clearing the stock display elements on the page to prepare them for new stock information, this function is about as minimal as loadStockList(). Notice that the stock name div element is set to "Loading..." so that the user knows data is in the process of being delivered. All of the other elements are blanked out until the request finishes. Upon completion, the stock information Ajax request gets handled by the handleStockInfoRequest() function, which looks like this:

Code View:
function handleStockInfoRequest() {
  if (request.readyState == 4 && request.status == 200) {
    // Store the XML response data
    var xmlData = request.responseXML.getElementsByTagName(
      "Stock")[0];

    // Display the detailed stock info
    replaceText(document.getElementById("stockname"),
      getText(xmlData.getElementsByTagName("Name")[0]) +
      " (" +
      getText(xmlData.getElementsByTagName("Symbol")[0]) +
      ")");
    replaceText(document.getElementById("stockprice"),
      "$" + getText(xmlData.getElementsByTagName("Last")[0]));
    replaceText(document.getElementById("stockcap"),
      "$" + getText(xmlData.getElementsByTagName("MktCap")[0]));
    replaceText(document.getElementById("stockvolume"),
      getText(xmlData.getElementsByTagName("Volume")[0]) +
      " shares");
    replaceText(document.getElementById("stockchange"),
      getText(xmlData.getElementsByTagName(
        "PercentageChange")[0]));
    if (getText(
      xmlData.getElementsByTagName(
      "PercentageChange")[0]).charAt(0) == '+')
      document.getElementById("stockchange").style.color = "#009900";
    else if (getText(
      xmlData.getElementsByTagName(
      "PercentageChange")[0]).charAt(0) == '-')
      document.getElementById("stockchange").style.color = "#990000";
    replaceText(document.getElementById("stockpe"),
      getText(xmlData.getElementsByTagName("P-E")[0]));
    replaceText(document.getElementById("stockdatetime"),
      getText(xmlData.getElementsByTagName("Time")[0]) + " - " +
      getText(xmlData.getElementsByTagName("Date")[0]));
  }
  ajaxUpdateState();
}

Remember that this function is handling XML data in the following format:

Code View:
<string>
  <StockQuotes>
    <Stock>
      <Symbol>SBUX</Symbol>
      <Last>36.29</Last>
      <Date>1/17/2007</Date>
      <Time>2:41pm</Time>
      <Change>+0.07</Change>
      <Open>36.26</Open>
      <High>36.52</High>
      <Low>36.20</Low>
      <Volume>4327880</Volume>
      <MktCap>N/A</MktCap>
      <PreviousClose>36.22</PreviousClose>
      <PercentageChange>+0.19%</PercentageChange>
      <AnnRange>28.72 - 40.01</AnnRange>
      <Earns>0.00</Earns>
      <P-E>N/A</P-E>
      <Name>STARBUCKS CP</Name>
    </Stock>
  </StockQuotes>
</string>

With this data format in mind, you can more easily see that the JavaScript code is navigating through the XML data and plucking out relevant pieces of information based upon the XML tag name. For example, the following two lines of code are used to grab the current stock price and set it as the value of the stock price span element:

replaceText(document.getElementById("stockprice"),
  "$" + getText(xmlData.getElementsByTagName("Last")[0]));

This code not only retrieves the stock price from the <Last> tag in the XML code, but also appends a dollar sign ($) to the value to clarify that it is a monetary value.

Another interesting bit of code in the handleStockInfoRequest() function relates to how the percentage change of the stock is displayed. The percentage is colored green or red to more clearly indicate whether the percentage change is a gain or loss. Here's the code that handles the color tweaking based upon the value of the percentage change:

if (getText(xmlData.getElementsByTagName(
  "PercentageChange")[0]).charAt(0) == '+')
  document.getElementById("stockchange").style.color = "#009900";
else if (getText(xmlData.getElementsByTagName(
  "PercentageChange")[0]).charAt(0) == '-')
  document.getElementById("stockchange").style.color = "#990000";

This code looks for a plus sign (+) or minus sign (-) preceding the percentage-change value as the basis for changing the color of the stockchange element to green (#009900) or red (#990000).

That finishes up the code for the Picker Web page, which is admittedly a little heftier than earlier examples. However, keep in mind that most of the JavaScript code is related to setting the various stock information elements. If you wanted to simplify the application to just show the current stock price, the JavaScript code would get a lot smaller. But what fun would that be?

The Quoter Server Script

Earlier in the chapter I explained how the Picker application requires a script on the server side to sidestep the limitation of not being able to make a direct Ajax client request on a third-party domain. The third-party domain is important because the Picker application relies on it for serving up live stock information. It is possible to use a PHP script as somewhat of a security proxy by accepting an Ajax request on behalf of the client, retrieving the stock data from the third-party server, and then responding to the client with the data. In this way, the Ajax request itself is made purely with respect to your own domain, and is therefore within the security limitations of Ajax.

The third-party Web service I'm talking about is webserviceX.net, which offers several XML-based data feeds. One of these feeds is a stock quote feed where you specify a ticker symbol and the server responds with an XML document containing detailed information about the stock. You've already seen the code within this XML document a couple of times throughout the chapter, but you haven't seen the PHP script that makes it possible to receive the code via an Ajax request. Following is the code for the quoter.php server script:

<?php
header('Content-Type: text/xml');

// Load the XML stock quote data from the server
$xml = html_entity_decode(file_get_contents(
  "http://www.webservicex.net/stockquote.asmx/GetQuote?symbol="
  . $_REQUEST['symbol']));

//
Return the XML stock quote data
echo $xml;
?>

Remember that the job of this script is to retrieve an XML document from the stock quote Web service at webserviceX.net, and then simply pass that data along to the client without any modifications. It is then up to the client to do something useful with the XML code, such as display portions of it on the page.

The server script begins by making sure that the response gets treated as XML. The second chunk of code in the script then loads the XML document from the stock quote Web service, making sure to pass along the symbol parameter so that the Web service knows which stock to look up. The last section of code is where the XML data is actually returned from the script, which serves as the response to the Ajax stock information request.

Before moving on to test the completed application, it's worth taking a quick moment to test the PHP script by itself. You saw how this is done in the previous chapter with the Booker application, but here's a sample URL for testing the Quoter script:

http://www.yourdomain.com/quoter.php?symbol=SBUX

Assuming the quoter.php file is stored on your server, change the domain to match yours in this line of code and then enter the URL into your Web browser. You can also try this trick directly on the live Linux CD that accompanies this book. Either way, Figure 4.5 shows the XML response data generated by the PHP script.

Figure 4.5. You can examine the XML stock information returned by the Quoter PHP script by opening the script directly in a browser.

[View full size image]

Feel free to experiment with different stock symbols in the URL for the Quoter script. This is a great way to study the data returned by a server script to make sure it is consistent with what you expected—it's much tougher to diagnose server script problems when all you're looking at is the client Web page.


ch04lev1sec4.html

Testing Picker

The Picker application is now all assembled and ready for a test. To try it out in your own browser, open the picker.html page in the chap04 folder on the accompanying live Linux CD. Figure 4.6 shows the application running with a stock selected from the initial list of hot stocks.

Figure 4.6. The Picker application begins by initially selecting the first stock type as well as the first stock in the stock list.

[View full size image]

The figure shows how Google is initially displayed as the first hot stock. To see the dynamic population of the selection list in action, select a different stock type from the first list. Figure 4.7 shows the application with Cold Stocks selected from the list.

Figure 4.7. Selecting a different stock type results in the dynamic reloading of the stock list as well as new stock information being displayed.

[View full size image]

Despite being a chocolate lover, I put the Hershey Company on the cold stock list. Because this stock is the first one in the list, its information is automatically loaded and displayed below the selection lists.

The last test for the application is to try choosing a different stock from the stock list. Figure 4.8 shows the application with a different stock (Amgen) selected in the cold stock list.

Figure 4.8. When you select a different stock, the stock list isn't reloaded, but new stock information is displayed on the page.

[View full size image]

You can see that the Picker application is deceptively simple in that the user interface is very basic and not a whole lot is going on visually. Behind the scenes, however, you know better. Two Ajax requests are made for every selection change in the stock type list, and one request is made each time you select a different stock in the stock list. Like any good Ajax application, the benefits are subtle, with a focus on improving the feel and responsiveness of traditional Web pages.


ch04lev1sec5.html

Giving Picker an Extreme Ajax Makeover

The Picker application does a pretty good job of presenting a dynamic user interface for selecting stock recommendations and then providing hard data to go along with each stock selection. The two-tiered selection list design of the application could certainly have benefits beyond investing. One idea I like involves using such an application to keep up with a collection of some kind, such as a movie collection.

When you think about the Picker application in a more abstract sense, you start to get a feel for how it could be applied to other types of data. In the case of a movie collection, the stock types could be converted to movie types, such as action, horror, comedy, etc. Within each movie type you would list your individual movies using a similar XML coding approach. However, in this case there is no established standard for uniquely representing a movie in shorthand as there is with stock ticker symbols. Instead, you may just want to go ahead and list the entire movie name because coming up with a "ticker symbol" for each movie would probably be difficult.

The primary challenge in creating a movie collection application based upon the Picker code is finding a Web service that can deliver movie information along the lines of how webserviceX.net delivers stock information in Picker. As it turns out, there is a Web service out there that makes the movie collection application a very tangible prospect with minimal work. Take a look at the following URL to see what I'm talking about:

http://www.trynt.com/movie-imdb-api/v2/?t=Raising%20Arizona

This Web service is called the TRYNT Movie IMDb Web Service, and it provides you with programmatic access to the popular Internet Movie Database (IMDb). If you've never explored the IMDb, feel free to do so at http://www.imdb.com/. Quite a few movie arguments have been resolved by that Web site! For more information about TRYNT, check out http://www.trynt.com/.

Getting back to the movie Web service, following is the XML data returned by the Raising Arizona URL you just saw:

Code View:
<trynt>
  <movie-imdb>
    <search>Raising Arizona</search>
    <matched-id>tt0093822</matched-id>
    <matched-url>http://www.imdb.com/title/tt0093822/
    </matched-url>
    <matched-title>Raising Arizona (1987)</matched-title>
    <data>
       <movie-id>
         <data>
           <id>tt0093822</id>
           <score>6</score>
         </data>
       </movie-id>
       <movie-title>
         <data>
           <id>Raising Arizona (1987)</id>
           <score>6</score>
         </data>
       </movie-title>
    </data>
  </movie-imdb>
</trynt>

Granted, there isn't a whole lot of useful information other than the year of the movie, which is unfortunately contained in the same field with the name, thus making it a bit tougher to extract. However, what is incredibly useful in this code is the link to the movie in the IMDb. This means you could dynamically build a link to the movie as part of the movie information displayed on the movie collection page. Making your application one click away from just about anything a person could want to know about a movie is quite a slick addition to the application.

To transform the Picker application into a movie collection application, it definitely wouldn't be a bad idea to redesign the XML tags in the stocks.xml file to make sense for a movies.xml file. Just keep in mind that every tag reference in the Web page would also need to be modified. Before you start ripping apart code, however, it might be worth taking a stab at altering the application purely by plugging movie data into the existing framework. Don't forget to change the first selection list in the Web page of the application so that it lists movie types instead of stock types.


ch04lev1sec6.html

Summary

This chapter presented you with the first sample application that makes multiple Ajax requests to different URLs. Fortunately, the requests occur back-to-back, not simultaneously; otherwise, the Ajax Toolkit would need to be modified to allow for multiple requests taking place at the same time. The Picker application is also a good example of how you can get around the limitation of not being able to make an Ajax request on a domain other than where the request originates. By putting this responsibility on a server script, you enable the client Web page to ask the server script to do the work of talking to the third-party server. In using a third-party Web service, the Picker application is a great example of how you can blend your own XML data (a list of stocks) with data from somewhere else (live stock quotes) that would be difficult if not impossible to come by otherwise.


ch05.html

Chapter 5. Tapping into RSS News Feeds

Ajax in Ancient Greece

Not to lessen the significance of asynchronous Web applications, but Ajax at one point in time had a much more significant meaning. I'm referring to ancient Greece, where a legendary Greek hero named Ajax figured heavily into the Trojan War. Ajax's legendary strength and courage were chronicled by the Greek poet Homer in the epic poem the Iliad.

As someone who has created and maintained numerous Web sites over the years, I have to say I was quite excited the first time I experimented with news feeds. They allow you to syndicate content from other places, and you can incorporate them into your own pages, with the net effect being that your pages update and stay refreshed automatically—or at least the news feeds do. So unless you have a knack and desire for painstakingly reporting the news, you may find that a relevant news feed injected into your site can provide interesting content that is automatically refreshed. And with a tiny amount of research, you can likely find a feed perfectly matched to your content.

This chapter shows how Ajax makes it possible to dynamically query a news feed for news items and then display these items on a page. The sample application you explore in this chapter provides a simple interface for selecting from multiple news services, in which case the list of news items updates to reflect the selected source. Almost as cool as the dynamic retrieval of news items via Ajax is the slick little "loading" image displayed while the Ajax request is being carried out.

The following files are used by the News Feeder application in this chapter, and are located on the live Linux CD-ROM with the book in the chap05 example code folder:

  • newsfeeder.html—Main Web page

  • newsfeeder.php—Server script for loading a news feed

  • newsfeeder.css—Style sheet for formatting news feeds

  • ajaxkit.js—Core Ajax functions for the Ajax Toolkit

  • domkit.js—DOM-related functions for the Ajax Toolkit

  • newspaper.gif—Newspaper icon that is displayed next to each news item

  • wait.gif—Animated "loading" icon that is displayed during an Ajax request

The Challenge: Querying News Feeds Dynamically

The challenge in this chapter is to use Ajax to dynamically query a news feed Web service for data (news items), and then display those news items on the page. More specifically, the news items are the titles of news stories, so what you actually need to display are news titles that serve as links to each individual news story. As it turns out, each news item in a news feed includes both a title and a link, among other things, so the news feed provides all the data you need to meet the challenge.

Before going any deeper into the challenge itself, we need to first take a moment to get up to speed on news feeds and how they fit into the Web equation. The technology that makes most news feeds tick is RSS. This technology allows you to syndicate Web content, which means you can subscribe to Web sites and easily find out about new publications to a site without actually having to visit it. Although there have been several interpretations of the RSS acronym, the latest and perhaps most accurate is Really Simple Syndication. RSS news feeds are actually XML documents that encode news information; you learn more about the specific format of RSS news feeds a bit later in the chapter.

Note

The history of RSS and its different versions is fairly complex, so suffice it to say that RSS 2.0 is the latest and most commonly used version of RSS. You may also see news feeds in the Atom format, which is very similar to RSS 2.0.

Using special software called a news aggregator, you can monitor RSS news feeds from multiple sites and effectively keep tabs on a wide range of information without having to stop by every different site on a regular basis. You can think of RSS as providing somewhat of a "stock ticker" for Web content—it allows you to keep constant tabs on when your favorite sites post something new.

Although they aren't as full-featured as standalone news aggregator applications, most modern Web browsers offer built-in support for viewing news feeds. Figure 5.1 shows the main Wired News feed as viewed in the Firefox browser.

Figure 5.1. You can view an RSS news feed directly in most Web browsers without any special plug-ins or software.

[View full size image]

Of course, viewing a news feed directly in a Web browser isn't quite the same as embedding a feed into your own pages. This brings us back to the challenge at hand—using Ajax to dynamically load and display a feed in a page. Because each news feed has its own unique URL, the Ajax part of the challenge is actually very straightforward—it involves retrieving an entire XML document from a URL. This means you don't have to do any special processing on the news data on the server side of the application, which simplifies things considerably.

Because the Ajax request for this application is so straightforward, we'll jazz up the user interface a little by giving the user a visual cue that the data is being loaded. This is also important because some news feeds contain enough information that there can be a noticeable delay in receiving the data. Even a delay of a few seconds can be confusing if you don't know what's going on. Therefore, a slick way to deal with the problem is to display a "loading" image while the request is taking place.

One last part of the challenge is to give the user the option of choosing from several news feeds. Not only does this provide a good way to stress-test the application with different data sets, but it also makes the application more flexible from the user's perspective. Of course, you may opt to pick a single feed and forego the selection approach when incorporating RSS into your own pages. Either way, the News Feeder sample application serves as a great starting point for your RSS Ajax adventures.


ch05lev1sec1.html

Chapter 5. Tapping into RSS News Feeds

Ajax in Ancient Greece

Not to lessen the significance of asynchronous Web applications, but Ajax at one point in time had a much more significant meaning. I'm referring to ancient Greece, where a legendary Greek hero named Ajax figured heavily into the Trojan War. Ajax's legendary strength and courage were chronicled by the Greek poet Homer in the epic poem the Iliad.

As someone who has created and maintained numerous Web sites over the years, I have to say I was quite excited the first time I experimented with news feeds. They allow you to syndicate content from other places, and you can incorporate them into your own pages, with the net effect being that your pages update and stay refreshed automatically—or at least the news feeds do. So unless you have a knack and desire for painstakingly reporting the news, you may find that a relevant news feed injected into your site can provide interesting content that is automatically refreshed. And with a tiny amount of research, you can likely find a feed perfectly matched to your content.

This chapter shows how Ajax makes it possible to dynamically query a news feed for news items and then display these items on a page. The sample application you explore in this chapter provides a simple interface for selecting from multiple news services, in which case the list of news items updates to reflect the selected source. Almost as cool as the dynamic retrieval of news items via Ajax is the slick little "loading" image displayed while the Ajax request is being carried out.

The following files are used by the News Feeder application in this chapter, and are located on the live Linux CD-ROM with the book in the chap05 example code folder:

  • newsfeeder.html—Main Web page

  • newsfeeder.php—Server script for loading a news feed

  • newsfeeder.css—Style sheet for formatting news feeds

  • ajaxkit.js—Core Ajax functions for the Ajax Toolkit

  • domkit.js—DOM-related functions for the Ajax Toolkit

  • newspaper.gif—Newspaper icon that is displayed next to each news item

  • wait.gif—Animated "loading" icon that is displayed during an Ajax request

The Challenge: Querying News Feeds Dynamically

The challenge in this chapter is to use Ajax to dynamically query a news feed Web service for data (news items), and then display those news items on the page. More specifically, the news items are the titles of news stories, so what you actually need to display are news titles that serve as links to each individual news story. As it turns out, each news item in a news feed includes both a title and a link, among other things, so the news feed provides all the data you need to meet the challenge.

Before going any deeper into the challenge itself, we need to first take a moment to get up to speed on news feeds and how they fit into the Web equation. The technology that makes most news feeds tick is RSS. This technology allows you to syndicate Web content, which means you can subscribe to Web sites and easily find out about new publications to a site without actually having to visit it. Although there have been several interpretations of the RSS acronym, the latest and perhaps most accurate is Really Simple Syndication. RSS news feeds are actually XML documents that encode news information; you learn more about the specific format of RSS news feeds a bit later in the chapter.

Note

The history of RSS and its different versions is fairly complex, so suffice it to say that RSS 2.0 is the latest and most commonly used version of RSS. You may also see news feeds in the Atom format, which is very similar to RSS 2.0.

Using special software called a news aggregator, you can monitor RSS news feeds from multiple sites and effectively keep tabs on a wide range of information without having to stop by every different site on a regular basis. You can think of RSS as providing somewhat of a "stock ticker" for Web content—it allows you to keep constant tabs on when your favorite sites post something new.

Although they aren't as full-featured as standalone news aggregator applications, most modern Web browsers offer built-in support for viewing news feeds. Figure 5.1 shows the main Wired News feed as viewed in the Firefox browser.

Figure 5.1. You can view an RSS news feed directly in most Web browsers without any special plug-ins or software.

[View full size image]

Of course, viewing a news feed directly in a Web browser isn't quite the same as embedding a feed into your own pages. This brings us back to the challenge at hand—using Ajax to dynamically load and display a feed in a page. Because each news feed has its own unique URL, the Ajax part of the challenge is actually very straightforward—it involves retrieving an entire XML document from a URL. This means you don't have to do any special processing on the news data on the server side of the application, which simplifies things considerably.

Because the Ajax request for this application is so straightforward, we'll jazz up the user interface a little by giving the user a visual cue that the data is being loaded. This is also important because some news feeds contain enough information that there can be a noticeable delay in receiving the data. Even a delay of a few seconds can be confusing if you don't know what's going on. Therefore, a slick way to deal with the problem is to display a "loading" image while the request is taking place.

One last part of the challenge is to give the user the option of choosing from several news feeds. Not only does this provide a good way to stress-test the application with different data sets, but it also makes the application more flexible from the user's perspective. Of course, you may opt to pick a single feed and forego the selection approach when incorporating RSS into your own pages. Either way, the News Feeder sample application serves as a great starting point for your RSS Ajax adventures.


ch05lev1sec2.html

The Design: Designing a News Feed Application

The design of the News Feeder application begins with the Ajax request that shuttles data from a news feed server to the application. This request begins with a URL for the feed server, which then returns an XML document containing detailed information about the news feed, including a list of individual news items with links and publish dates. The Ajax request is triggered by the user selecting a news feed from a selection list.

Given that each news feed has its own URL that is used as the basis for the Ajax request, you need a way to tie a feed URL to a feed name for the purposes of allowing the user to select a feed. The value attribute of the <option> tag is the perfect place for storing the URL for a feed, and it allows you to build a news feed selection list with ease.

The news feed selection list serves as a major component of the News Feeder user interface. This interface consists of two parts: the news feed selection list and an area for displaying the feed data once it is successfully loaded. Feed data in this case consists of the feed title and a listing of individual feed items that serve as links to each news story. Figure 5.2 shows how the News Feeder user interface factors into the news feed Ajax request.

Figure 5.2. The user interface for the News Feeder application consists of a selection list and an area containing the news feed title and individual news item links.

Earlier I mentioned that the application should make use of an animated image to let the user know when an Ajax request is busy downloading news feed data. Figure 5.3 shows what this animated image, wait.gif, looks like.

Figure 5.3. The News Feeder application makes use of an animated "loading" image (wait.gif) to let the user know the Ajax request is being processed.

Granted, it's hard to make out the animation on the printed page, but the movement of the image gives users a sense that something is taking place and that they're not just staring at a frozen page. Now is the time when you might question the idea of displaying a "loading" image in an asynchronous application. Isn't the whole point of Ajax to not ever make the user wait on something? Yes, but keep in mind that the application actually isn't frozen during the request—the user is free to select a different news feed, in which case the current feed request is interrupted and the new feed is loaded. The animated image is just there to let the user know that some kind of work is being done in the background.

You should now have a good enough feel for the application's general design to dig a little deeper into the Ajax request and response.

The Client Request

Without any security limitations, the client request in the News Feeder application would be the most predictable part of the Ajax equation because it would simply perform a GET request on a URL with no special parameters or anything else. However, it isn't possible to make an Ajax request directly on a remote Web server, which means you must create your own server script to accept the Ajax request and fulfill it.

All that is required to obtain news feed data is the URL of a news feed Web server. Therefore, the News Feeder client request must send along the URL of the news feed to your server script, which then handles getting the data and returning it in an Ajax response. The key to all this is identifying suitable RSS news feeds, which means finding their URLs.

If you start to pay attention to the Web sites you visit, you might see a "syndicate" link or possibly even an RSS icon somewhere near the main menu or navigation links. This is how you find the URL for a news feed, and this URL is all you need to load the news feed via Ajax.

Note

Most content-driven Web sites such as news Web sites offer numerous news feeds that are specific to different interests. For example, USA Today offers over 30 different sports feeds ranging from college hockey to horse racing. To access them, just scroll to the bottom of the main USA Today Web page (http://www.usatoday.com/) and click the little orange XML icon. This icon is often used instead of the newer RSS icon.

The Server Response

On the server side of the News Feeder application, the server is responsible only for delivering an XML document containing the news feed information in the RSS data format, which is an XML format. Unlike some of the other examples in the book, which rely on a server PHP script in order to somehow process or manipulate data before returning it in an Ajax response, the News Feeder application only requires a PHP script to get around the inherent limitation of not being able to issue a client request on a third-party domain. This is a security restriction that prevents client-side JavaScript code from venturing beyond the domain from which it is served.

The News Feeder application therefore does need a PHP script on the server, but its only role is to grab news feed data from a remote server and then shuttle it back to the client via an Ajax response. You can think of the server script for News Feeder as a proxy in that it serves as the middle man between the client JavaScript code and the remote server that actually hosts the news feed. Again, the key is that your Ajax code can only make requests to your server, which is a big problem when you need to request data from somewhere else. The solution is to allow a server script to retrieve the data, and then have that script serve as the basis for responding to Ajax requests.

The third-party (remote) servers I keep talking about can be any server that sources data in the RSS format. You'll find that if you do a little exploring, most major Web sites offer news feeds in the RSS format. Just take note of the URL in your browser when you find a news feed—this is the URL you'll plug into your code when making an RSS Ajax request.

Making Sense of the Client-to-Server Conversation

If you put together what you've learned about the communication that takes place within the context of the News Feeder application, you get a flow of data as shown in Figure 5.4.

Figure 5.4. The News Feeder application receives XML news feed data in response to making a request with a news feed URL.

The data sent to the server as a parameter of the Ajax request is the URL of the news feed data source. Although this data is always in the form of a URL, it can take several forms. For example, following is the URL for the news feed associated with the Scientific American Web site: http://www.sciam.com/xml/sciam.xml.

Notice that this URL references a specific XML document, sciam.xml. This makes sense given that RSS feeds are actually XML documents, but news feed URLs don't always reference XML files. As an example, the following URL is for the Wired News feed: http://feeds.wired.com/wired/topheadlines.

In this example, the URL is a path as opposed to a filename. The bottom line is that you can't always predict the exact form of a news feed URL. The good news is that you can usually just take and use the syndication URL as provided to you by a Web site.

Once you know the URL of a news feed Web server, it needs to get packaged into a larger URL for submission to the News Feeder server script as part of an Ajax request. Here's an example of how this is done:

newsfeeder.php?rssurl=http://www.sciam.com/xml/sciam.xml

This code reveals how the news feed URL is packaged into a URL as a single parameter (rssurl). This entire URL is used as the basis for an Ajax request, in which case your server script, newsfeeder.php, will take the rssurl parameter and use the URL it contains to obtain the feed information.

Speaking of the server script, you now understand that it receives the news feed URL via the rssurl parameter and then uses the URL to retrieve an RSS document. This document is then passed back to the client JavaScript code through an Ajax response. Following is an example of what such RSS code actually looks like:

Code View:
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
  <title>Scientific American - Official RSS Feed</title>
  <link>http://www.sciam.com/</link>
  <image>
    <url>http://www.sciam.com/media/logo/SAlogo_144px.gif</url>
    <title>Scientific American.com</title>
     <link>http://www.sciam.com/</link>
    <width>144</width>
    <height>45</height>
  </image>
  <description>Science news and technology updates from
    Scientific American</description>
  <language>en-us</language>
  <managingEditor>editors@sciam.com</managingEditor>
    <dc:publisher>Scientific American</dc:publisher>
  <copyright>Copyright 1996-2007 Scientific American</copyright>
  <item>
    <title>News: Snake Bites the Toxic Toad That Feeds It—and
      Spreads Its Poison</title>
    <link>http://www.sciam.com/article.cfm?chanID=sa003&amp;
      articleID=6FD96483-E7F2-99DF-3C8A12ACF6BB25D8&amp;
      ref=rss</link>
    <guid>http://www.sciam.com/article.cfm?chanID=sa003&amp;
      articleID=6FD96483-E7F2-99DF-3C8A12ACF6BB25D8&amp;
      ref=rss</guid>
    <author>JR Minkel &lt;editors@sciam.com&gt;</author>
    <dc:date>2007-01-29T17:00:00-05:00</dc:date>
  </item>
  <item>
    <title>News: Did Honest Abe Have Nerves of Glass?</title>
    <link>http://www.sciam.com/article.cfm?chanID=sa003&amp;
      articleID=6FD6E124-E7F2-99DF-3E0EDA7A34E03A06&amp;
      ref=rss</link>
    <guid>http://www.sciam.com/article.cfm?chanID=sa003&amp;
      articleID=6FD6E124-E7F2-99DF-3E0EDA7A34E03A06&amp;
      ref=rss</guid>
    <author>Nikhil Swaminathan &lt;editors@sciam.com&gt;</author>
    <dc:date>2007-01-29T17:00:00-05:00</dc:date>
  </item>
...
</channel>
</rss>

At first glance this code looks a little threatening, but much of it can be ignored for our purposes. Keep in mind that the challenge of the News Feeder application is to display a list of news items that link to the actual news stories. You can extract this data from the XML document and ignore a lot of the other details. To see what I'm talking about, look through the code and find an <item> tag. Now look immediately below that tag and find tags called <title>, <link>, and <dc:date>. The code looks like this:

...
  <item>
    <title>News: Snake Bites the Toxic Toad That Feeds It—and
      Spreads Its Poison</title>
    <link>http://www.sciam.com/article.cfm?chanID=sa003&amp;
      articleID=6FD96483-E7F2-99DF-3C8A12ACF6BB25D8&amp;
      ref=rss</link>
...
    <dc:date>2007-01-29T17:00:00-05:00</dc:date>
  </item>
...

The <title> tag stores a single news item title, whereas the <link> tag stores its associated link. The <dc:date> tag can actually be thought of simply as the <date> tag because the dc part is a namespace prefix and not technically part of the tag name. Most RSS feeds actually use the <pubDate> tag to encode the publish date instead of the <date> tag, so it would be wise to factor in both options when processing the XML data. It's also important to consider the possibility of a news item not having either of these tags because the publish date is optional in RSS documents. The bottom line to all of this RSS tag talk is that you can drill through the code, extracting specific tags and their content to build a news item list without too much trouble.

Note

The reason why two different tags are used to encode the publish date in RSS news feeds is complicated and has to do with competing specifications and the fact that the RSS format has evolved rapidly. Rather than give you a boring and unnecessary history lesson of RSS, I'll suffice it to say that you will likely encounter the <pubDate> tag much more often than <date> (<dc:date>), but it is still worth supporting both because a few prominent sites do use <date>.

Of course, you also need to obtain the name of the news feed, and perhaps even a link to its Web site. This information is also contained within <title> and <link> tags, but this time the tags appear beneath the <channel> tag; a distinct news feed is also sometimes referred to as a channel, as in a television channel. So, examining the Scientific American code once more, following is the code containing the news feed title and link:

...
<channel>
  <title>Scientific American - Official RSS Feed</title>
  <link>http://www.sciam.com/</link>
...

To summarize, the following pieces of information must be plucked from the RSS (XML) news feed document for the purposes of the News Feeder application:

  • News feed title (<title> inside of <channel>)

  • News feed link (<link> inside of <channel>)

  • News item titles (<title> inside of <item>)

  • News item links (<link> inside of <item>)

  • News item publish dates (<pubDate> or <date> inside of <item>)

The first two pieces of information only occur once in any given news feed document, whereas the latter two can appear multiple times if there are multiple news items—and there usually are. When there are multiple news items, each of the items has its own <item> tag.

Although I could spend a lot more time revealing the finer points of the RSS data format, I won't; it's just not necessary. You have all you need to know to put together the News Feeder application, so let's get to it!


ch05lev1sec3.html

Putting Together the News Feeder Application

You're probably ready for the major parts of the News Feeder application: a Web page and a server script. However, there is also a third piece of the puzzle in the form of a CSS style sheet. The style sheet is not absolutely necessary, but it does add a considerably more pleasant look to the news information that is displayed. So, following are the components required for the application:

  • HTML Web page (newsfeeder.html)

  • CSS style sheet (newsfeeder.css)

  • PHP server script (newsfeeder.php)

Keep in mind that a remote server is also involved in this equation for each different news feed URL. This remote server isn't part of the application in a sense that there are no files or other resources you have to worry about, but it does nonetheless play a crucial role in the functioning of the application. So as you work through the News Feeder application files in the next few sections, understand that they are still dependent upon a remote server for getting the actual news feed data.

The News Feeder Web Page

The News Feeder Web page (newsfeeder.html) is undoubtedly the most significant part of the application because it is responsible for making sense of the RSS data sent back from the PHP server script and displaying this data in a meaningful fashion. As revealed in Figure 5.5, this page contains a news feed selection list followed by a div element that contains the linked title of the currently selected news feed, along with a list of each linked news item.

Figure 5.5. The News Feeder Web page consists of a news feed selection list followed by information related to the currently selected feed.

[View full size image]

The HTML code establishes the user interface for the News Feeder Web page in the <body> tag, whose code follows:

Code View:
<body onload="loadFeed()">
  <div id="ajaxState" style="display:none"></div>
  <br />
  <div>Choose your news:
    <select id="feed" onchange="loadFeed()">
      <option value="http://feeds.wired.com/wired/topheadlines">
        Wired News</option>
      <option value=
        "http://feeds.engadget.com/weblogsinc/engadget">
        Engadget</option>
     <option value=
       "http://feeds.ziffdavis.com/ziffdavis/extremetech">
       ExtremeTech</option>
     <option value=
       "http://feeds.feedburner.com/ajaxian">Ajaxian</option>
     <option value="http://www.sciam.com/xml/sciam.xml">
       Scientific American</option>
     <option value="http://news.google.com/?output=rss">
       Google News</option>
     <option value=
       "http://www.michaelmorrison.com/mambo/index2.php?
       option=com_rss&feed=RSS2.0&no_html=1">
       Michael Morrison's Blog</option>
   </select>
 </div>
 <br />
 <div id="feedcontent"></div>
</body>

If you exclude the selection list created by the <select> tag, you'll see that this code is quite minimal. In fact, there are really only two visual elements on the page: the selection list (feed) and a div element (feedcontent) used to display the dynamically loaded news feed information.

One piece of code that shouldn't get overlooked in the Web page body is the onload event handler, which is responsible for loading feed data for the first news feed in the selection list with a call to the loadFeed() function. Before you see the loadFeed() function, it's worth pointing out that you can fully customize the News Feeder application with news feeds you've found without dealing with any of the other code in the page. In other words, you can completely customize the application without looking at any of the remaining JavaScript code—just add new <option> tags or modify the existing <option> tags with different news feed titles and URLs.

If you want to go a bit deeper and understand how things work behind the scenes of the application, then of course you'll have to dig into the JavaScript code. Following is the code for the loadFeed() function, which is responsible for initiating the Ajax request that loads news feed data:

function loadFeed() {
  // Clear the previous feed content
  document.getElementById("feedcontent").innerHTML =
    "<img src='wait.gif' alt='Loading...' />";

  // Send the Ajax request to load the new feed content
  ajaxSendRequest("GET", "newsfeeder.php?rssurl=" +
    encodeURIComponent(document.getElementById('feed').options[
    document.getElementById('feed').selectedIndex].value),
    handleFeedRequest);
}

The first thing the loadFeed() function does is one of the most interesting features of the application, and that is display the animated "loading" image (wait.gif) that appears while the request is being processed. This image was shown back in Figure 5.3, but it makes much more sense when seen in context—check out Figure 5.6.

Figure 5.6. An animated "loading" image is used to let the user know that a news feed Ajax request is being processed.

[View full size image]

Getting back to the loadFeed() code, the "loading" image is displayed by changing the div with the ID of feedcontent so that it contains an <img> tag. This change is accomplished by setting the innerHTML property of the div element. You can use the innerHTML property to dynamically alter the content of an element on the page. You see this property used again in just a moment in the code that displays the news feed title and news items in the same feed content div.

The last chunk of code in the loadFeed() function takes care of issuing the Ajax request. This code builds a URL for communicating with the PHP server script, newsfeeder.php, including the rssurl parameter that contains the news feed URL. The Ajax handler function is set to handleFeedRequest(), and it is this function that does the heavy lifting in the application.

Note

At this point I have to let you in on a little secret—this is the first time in the book I've used the innerHTML property to change the content in a Web page. I feel a little guilty because this property isn't officially endorsed by the World Wide Web Consortium (W3C) as a Web standard, making its usage somewhat questionable. However, it is incredibly handy and is used in countless Web sites by expert developers, making it unlikely this property will go away any time soon. The alternative is to modify content in the page purely through DOM Application Programming Interface (API) functions. This latter technique is preferred, at least from a standards perspective, but in most cases it is more complex. I opted to err on the side of simplicity, and thus used the innerHTML property. If you want to learn more about the innerHTML versus DOM API debate, just do a Web search on "innerHTML" and "DOM." You won't find a shortage of strong opinions!

Before getting into the code for the handleFeedRequest() function, there is one other little piece of code worth addressing. I'm talking about the code just below the loadFeed() function that preloads the wait.gif image:

var waitImage = new Image();
waitImage.src = "wait.gif";

The significance of this code is that you don't want any noticeable delay in loading the "loading" image. The whole point of the image is to let the user know that something meaningful is going on behind the scenes. So, we get the ball rolling as quickly as possible by preloading the image before the page is even rendered. This works because the image preloading code appears outside of any other JavaScript functions, which means that it is automatically run when the page is loaded.

Getting back to the handleFeedRequest() function, its job is to react to an Ajax response by picking through the RSS data returned and then displaying meaningful news feed information. Following is the code for this function:

Code View:
function handleFeedRequest() {
  if (request.readyState == 4 && request.status == 200) {
    // Store the XML response data
    var xmlData = request.responseXML;

    // Generate the feed content by starting with the feed title
    var feedContent = "";
    var channelElem = xmlData.getElementsByTagName("channel")[0];
    feedContent += "<div class='feedtitle'><a href='" +
      getText(channelElem.getElementsByTagName("link")[0]) +
      "'>" + getText(channelElem.getElementsByTagName(
      "title")[0]) + "</a></div>";

    // Now generate the list of feed items as an unordered list
    feedContent += "<ul>";
    var feedItems = channelElem.getElementsByTagName("item");
    for (var i = 0; i < feedItems.length; i++) {
      var itemTitle =
getText(feedItems[i].getElementsByTagName("title")[0]);
      var itemLink = getText(feedItems[i].getElementsByTagName(
        "link")[0]);
      var itemPubDate =
getText(feedItems[i].getElementsByTagName("pubDate")[0]);
      if (itemPubDate == "")
        itemPubDate = getText(feedItems[i].getElementsByTagName(
          "date")[0]);
      if (itemPubDate == "")
        feedContent += "<li><a href='" + itemLink + "'>" +
          itemTitle + "</a></li>";
      else
        feedContent += "<li><a href='" + itemLink + "'>" +
          itemTitle + " <span class='itemdate'>(" +
          itemPubDate + ")</span></a></li>";
    }
    feedContent += "</ul>";

    // Display the feed content
    document.getElementById("feedcontent").innerHTML = feedContent;
  }
  ajaxUpdateState();
}

Admittedly, there is a fair amount of code here, but it isn't too terribly difficult to figure out. Just keep in mind that it is basically constructing a chunk of HTML code on the fly. In other words, the function is building a portion of a Web page so that it can be inserted into the feed content div for display. The generated HTML code contains the title of the news feed, which also happens to serve as a link to the news source Web site. The HTML code also contains an unordered (bulleted) list of news items that each consists of a linked title and a publish date. It's important to note that the generated HTML code contains a couple CSS style sheet class references, which helps the style sheet know which content it is applied to.

Near the end of the handleFeedRequest() function you see a line of code that finally inserts the dynamically generated HTML code into the page:

document.getElementById("feedcontent").innerHTML = feedContent;

Although short and sweet, this single line of code does quite a lot when you consider that it is responsible for replacing the "loading" image with the carefully formatted news feed title and news items.

The look of the News Feeder page is provided primarily by the newsfeeder.css style sheet, which is referenced in the Web page head via the following link:

<link rel="stylesheet" type="text/css" href="newsfeeder.css" />

The newsfeeder.css style sheet is located in the same chap05 folder as the rest of the News Feeder source files. The next section quickly examines this style sheet and explains how it impacts the final look of the News Feeder application.

The News Feeder Style Sheet

I'll be the first to admit that I'm quite reluctant to list CSS style sheet code in a book about Ajax. However, the News Feeder application is an excellent example of how much pizzazz a style sheet can add to an application in a relatively small amount of code. If you don't believe me, check out Figure 5.7, which shows the News Feeder application without the benefit of the style sheet.

Figure 5.7. When the style sheet is removed, the News Feeder application looks somewhat dull.

[View full size image]

Compare this figure to Figure 5.5, which shows the exact same news feed with the benefit of the style sheet. Or just pop in the Live Linux CD that comes with the book and try out the News Feeder example in your own Web browser. The point is that even though CSS has nothing directly to do with Ajax, it can make just about any Ajax application look significantly more appealing and professional.

Following is the CSS code responsible for styling the news feed title in the News Feeder application:

div.feedtitle {
  padding-left : 5px;
  background-color : #EEEEEE;
  font-size : 22px;
  font-weight : bold;
}

div.feedtitle a {
  color : #666677;
  text-decoration : none;
}

div.feedtitle a:hover {
  color : #333344;
  text-decoration : none;
}

The news feed title is generated in HTML code that has a class attribute of feedtitle, which is what links the code to this group of styles. The left-side padding, background color, font size, and font weight are first established for the title as a whole. Then the color of the text is set, along with a slightly different color for when the user hovers the mouse over the title (it is a link, if you recall). The text-decoration style is used to override the default HTML behavior of underlining a link when the user hovers over it—changing the font color on a hover is a bit cleaner and more professional looking in this case.

Similar CSS styles are applied to the individual news items that appear in the unordered list:

li {
  font-size : 18px;
  padding-left : 25px;
  background : url(newspaper.gif) no-repeat;
  list-style : none;
}

This is the code responsible for the neat little newspaper icons that appear next to each item in the list (refer to Figure 5.5). Each list item is also a link, so it makes sense to apply the same general "link hover" coloring concept to the news items as was done for the feed title. Here's the CSS code for it:

a:link {
  color : #333344;
  text-decoration : none;
}

a:visited {
  color : #9999AA;
  text-decoration : none;
}

a:hover, a:active {
  background : #EEEEEE;
  text-decoration : none;
}

Finally, you might have noticed that the publish date for each news item appears in italics and in a very light color so as not to compete with the title. Following is the CSS style responsible for the look of the publish dates of the news items:

span.itemdate {
  font-style : italic;
  color : #CCCCDD;
}

That wraps up the style sheet for the News Feeder application. All that's left is the PHP server script and this application will be finished.

The News Feeder Server Script

Have you ever seen a relay event in track and field where one runner hands a baton to another runner? That's pretty much what the newsfeeder.php server script does for the News Feeder application. It runs off and grabs the news feed RSS data from a remote server, and then hustles back and hands that data off to the client JavaScript code. The server script knows what server to grab the RSS data from, thanks to a URL parameter (rssurl) passed to it in an Ajax request. Following is the code for this PHP script:

<?php
header('Content-type: text/xml;');

// Return the RSS feed data
echo file_get_contents($_REQUEST['rssurl']);
?>

Note

Remember that the purpose of this "proxy" server script is to get around the limitation of not being able to issue Ajax requests on remote servers. If this security limitation didn't exist, the server script would be unnecessary and the client would just make an Ajax request directly on the news feed URL. However, there is a good reason why remote request permission is limited to servers: security! It would be far too dangerous to give client scripts free reign to initiate remote requests, so having to create your own Ajax proxy is a small price to pay for a safer Web.

After setting the header so that the response is sent as XML, this script really only consists of one line of code. The file_get_contents() function retrieves data from a specified URL, which is exactly the functionality you need. So, all the script does is pass the news feed URL into this function and echo the results back to the client. The end result is a cleanly formatted RSS news feed document that is sent back to the client as a response to the Ajax request.


ch05lev1sec4.html

Testing the News Feeder

When you first open the News Feeder Web page, the application initially loads the first news feed in the selection list, which happens to be the top stories from Wired News. Figure 5.8 shows the application with this news feed selected.

Figure 5.8. The News Feeder application begins by loading the first news feed in the selection list.

[View full size image]

When you change to another news feed by selecting a different feed in the selection list, the animated "loading" image is displayed while the Ajax request is made. Figure 5.9 shows the feed being changed from Wired News to Engadget.

Figure 5.9. When you change the news feed, the animated "loading" image is displayed to let you know that the page is working on something in the background.

[View full size image]

News feeds aren't terribly large in size, so it shouldn't take long at all for the new feed to be displayed. When this does take place, the information for the new feed replaces the "loading" image on the page, as shown in Figure 5.10.

Figure 5.10. When a newly selected news feed finishes loading, the feed information replaces the "loading" image on the page.

[View full size image]

It's important to point out that you have now created a surprisingly handy little news aggregator of your own. What I mean is that once you get past the immediate aspect of how Ajax works in the News Feeder application, you may find that you actually enjoy using the application to obtain news. Just click a news item to follow its link to the complete news story. In this case, clicking a news item leads you to the news story on the Engadget Web site.

In addition to having interesting gadget news, the Engadget Web page is also a great example of how a site with an RSS news feed makes it easy for you to syndicate the feed. Look in the upper-right corner of the Engadget Web page and you'll see the standard orange icon for RSS. Click this icon and you'll get the URL for the Engadget news feed, which is a good one I might add!


ch05lev1sec5.html

Giving News Feeder an Extreme Ajax Makeover

No application in this book is ever truly complete. By that I mean that the Sample applications are all meant to be starting points for you to experiment with Ajax on your own. The News Feeder application is no exception, and in fact it is a great example of an application that is extremely customizable.

Perhaps the most obvious way to customize the News Feeder application is to tinker around with the feeds themselves. This is also the simplest customization because all you have to do is manipulate the <option> tags in the Web page, changing titles and values so that they correspond to other news feeds. Keep in mind that you can add as many new <option> tags as you want, ultimately building a selection list with numerous different news feeds. Just make sure to place the name of the feed between the <option> and </option> tags and then stick its URL in the value attribute.

You may decide that being able to choose from a list of news feeds isn't exactly what you want, in which case you may elect to simply embed a single news feed in a Web page of your own. In this case, you need to carefully extract the important code from the newsfeeder.html Web page and place it into your page. This primarily involves copying and pasting all of the script code in the head of the page, as well as making sure not to forget the onload event handler for the <body> tag, which calls the loadFeed() function. You also need to make sure you create a div element named feedcontent. And finally, you need to tweak the loadFeed() function slightly so that it uses the news feed URL of your choice instead of grabbing it from the selection list.

If you elect to embed a news feed into a page that has other content, there's a good chance you will want to limit the number of news items displayed on the page. For example, you may only want to display the first five or ten news items. To limit the number of items shown, change the for loop in the handleFeedRequest() function to this:

for (var i = 0; (i < feedItems.length) && (i < numItems); i++) {

In this code, the numItems variable controls how many news items are displayed. You can either use a variable or just hard-code a number, such as this:

for (var i = 0; (i < feedItems.length) && (i < 10); i++) {

This example limits the number of news items to ten. The for loop still checks the length of the feedItems array just in case the news feed has less than ten items in it, in which case you only want the number of available items displayed.

The final trick you might want to consider now that you have some RSS skills is to create an RSS news feed of your own. Whether you have a blog or some other Web site with content that changes on a regular basis, allowing users to syndicate your site is a neat feature. You've hopefully gleaned enough in this chapter about the RSS format to take a stab at creating your own RSS documents. In fact, the ideal solution is to develop a script that automatically converts HTML Web content into RSS form so that your site becomes automatically syndicated. The specifics of that solution are a bit beyond the scope of this chapter, but you now have a great tool to test out your news feeds should you create any.


ch05lev1sec6.html

Summary

This chapter introduced you to an exciting area of Web content management known as news feeds, which use a standard XML-based data format known as RSS (Really Simple Syndication). Using RSS, it is possible to get a snapshot of the changing content on a Web site without actually having to visit the Web site. More importantly, it becomes possible to syndicate content from another Web site and make it available on your Web site. This is a great way to keep your pages fresher without having to always dream up your own content. The News Feeder application you developed in this chapter demonstrated how Ajax makes it possible to dynamically load RSS data and present it on the page cleanly so that news items can be navigated and read. The application contains enough core code so that you can inject RSS news feeds into your own Web pages with little effort.


ch06.html

Chapter 6. Reading the User's Mind with Auto-Complete

Ajax the Thoroughbred Racehorse

If you had been a gambler in Australia in the 1930s, you might've thought of Ajax in a much different light. You could've made quite a bundle betting on Ajax the champion Australian thoroughbred racehorse, who is remembered for winning 18 races in a row and was later inducted into the Australian Racing Hall of Fame.

When Ajax first hit the Web scene, one of the most immediately beneficial examples of it was Google Suggest, which uses Ajax to assist you in performing searches by attempting to auto-complete the search text. Google Suggest is a particularly compelling example of Ajax because it is both subtle and powerful—a tough combination to put together. Too many technological Web improvements have ended up being distracting to the Web experience despite their technical merits. Not so with Ajax. Google Suggest's auto-complete feature is one of many Ajax features that dramatically improve the Web experience without interfering with it.

This chapter guides you through the design and development of an auto-complete application that uses Ajax to dynamically look up user input on the server and assist with a possible input completion. In some ways, you can think of this application as a rudimentary form of artificial Web intelligence because it gives a text input control the ability to guess what the user is typing. The application is both simple and powerful, and is a very handy tool to add to your Ajax arsenal.

The following files are used by the Completer application in this chapter, and are located on the live Linux CD-ROM with the book in the chap06 example code folder:

  • completer.html—Main Web page

  • completer.php—Server script for looking up auto-completion text

  • ajaxkit.js—Core Ajax functions for the Ajax Toolkit

  • domkit.js—DOM-related functions for the Ajax Toolkit

The Challenge: Anticipating Data Entry

The challenge in this chapter is to create an application with functionality similar to the auto-complete feature made popular by Google Suggest. Before you go any further, it would be helpful to take a quick look at Google Suggest to see exactly how it works. So point your browser at http://www.google.com/webhp?complete=1&hl=en and try performing a search.

Note

Google Suggest is still considered an experimental project within the Google Labs area of Google, which is why it has such a cryptic URL. You may see this URL change to something more readable if Google Suggest is ever promoted to mainstream use within the Google search engine.

Google Suggest is actually fairly sophisticated in that it dynamically displays a dropdown list from which to choose suggested search phrases. Google Suggest is interesting because it also displays the number of hits for each suggestion, thereby giving you some kind of gauge for the importance of the suggestion. What Google Suggest doesn't do is manipulate the text field itself in any way, unless of course you choose one of the suggestions from the dropdown list.

The Completer application you develop in this chapter takes a slightly different approach to the auto-complete feature than Google Suggest. To get a feel for how it will work, let's check out another handy Web site that offers auto-complete, Lyricsfly.com. Feel free to surf on over to http://www.lyricsfly.com/, which is shown in action in Figure 6.1.

Figure 6.1. Lyricsfly.com is a music lyric search engine that uses the auto-complete feature.

[View full size image]

In the figure I've clicked the Song link to search specifically for songs. Also notice in the figure the major distinction between Lyricsfly.com and Google Suggest—Lyricsfly.com actually adds the suggested text to the text field as it makes suggestions. This means you don't have to use the dropdown list if you don't want to. In fact, it means you really don't need the dropdown list at all if you don't mind continuing to type and hone in on the song. Granted, the dropdown list is a big help, and it does convey extra information such as the artists, but it isn't essential to the auto-complete feature. Figure 6.2 reveals how the dropdown list in Lyricsfly.com will eventually resolve to a single song if you continue to type the song name.

Figure 6.2. The more you type into Lyricsfly.com, the less critical the dropdown list becomes.

[View full size image]

In this figure I've entered enough of the song name to reduce the dropdown list to a single song. Of course, the whole idea is to prevent the user from having to type a lot, but you get the idea that the auto-complete feature could function reasonably well without the dropdown list.

The main point in showing how auto-complete can be implemented without a dropdown list is to set up the challenge for the Completer sample application. There is a fair amount of complexity in dynamically creating and managing a custom dropdown list, and I want to keep this example as clean as possible. You get to Ajax-driven custom popup windows later in the book, but for now I want to stick with a simple user interface without a bunch of tricky overhead code. Therefore, we'll scrap the dropdown list and create an auto-complete feature purely within a text input control.

This means the application will only be suggesting one word or phrase at any given time, but you'll see that even a single suggested phrase can go a long way toward making an application more helpful and intuitive.

So the task at hand for the Completer application is to provide an auto-complete feature solely for a text input control. In terms of how this challenge impacts Ajax, the client part of the application is responsible for sending the server the text the user is entering as each character is typed. The server takes a given piece of input text and finds the closest match in its list of possible completions (suggestions). The server then returns the remaining part of the completion to the client so that it can be added to the text input control and selected.

To make the application mildly educational, Completer uses a list of famous historical people as the basis for its auto-complete functionality. This means the user will begin by starting to enter a name, and the application will quickly (ideally) fill in the text field with its best guess as to who the person might be. If the user is happy with the suggestion, he or she doesn't need to type any more. If not, the user can elect to continue typing and the application will try again with another completion attempt. Unless the user is typing too fast for the Ajax requests to keep up, a request will be made for each individual keypress (key release, actually, but that's not the point).

In summary, the Completer application issues an Ajax request for each character entered by the user in an attempt to automatically complete the entry of a historical name. Once the name is successfully entered, the user can click a button to view a biography of the historical person on Wikipedia, the popular online encyclopedia. The Wikipedia facet of the application is just a token prize for successfully using Ajax to enter a historical name.


ch06lev1sec1.html

Chapter 6. Reading the User's Mind with Auto-Complete

Ajax the Thoroughbred Racehorse

If you had been a gambler in Australia in the 1930s, you might've thought of Ajax in a much different light. You could've made quite a bundle betting on Ajax the champion Australian thoroughbred racehorse, who is remembered for winning 18 races in a row and was later inducted into the Australian Racing Hall of Fame.

When Ajax first hit the Web scene, one of the most immediately beneficial examples of it was Google Suggest, which uses Ajax to assist you in performing searches by attempting to auto-complete the search text. Google Suggest is a particularly compelling example of Ajax because it is both subtle and powerful—a tough combination to put together. Too many technological Web improvements have ended up being distracting to the Web experience despite their technical merits. Not so with Ajax. Google Suggest's auto-complete feature is one of many Ajax features that dramatically improve the Web experience without interfering with it.

This chapter guides you through the design and development of an auto-complete application that uses Ajax to dynamically look up user input on the server and assist with a possible input completion. In some ways, you can think of this application as a rudimentary form of artificial Web intelligence because it gives a text input control the ability to guess what the user is typing. The application is both simple and powerful, and is a very handy tool to add to your Ajax arsenal.

The following files are used by the Completer application in this chapter, and are located on the live Linux CD-ROM with the book in the chap06 example code folder:

  • completer.html—Main Web page

  • completer.php—Server script for looking up auto-completion text

  • ajaxkit.js—Core Ajax functions for the Ajax Toolkit

  • domkit.js—DOM-related functions for the Ajax Toolkit

The Challenge: Anticipating Data Entry

The challenge in this chapter is to create an application with functionality similar to the auto-complete feature made popular by Google Suggest. Before you go any further, it would be helpful to take a quick look at Google Suggest to see exactly how it works. So point your browser at http://www.google.com/webhp?complete=1&hl=en and try performing a search.

Note

Google Suggest is still considered an experimental project within the Google Labs area of Google, which is why it has such a cryptic URL. You may see this URL change to something more readable if Google Suggest is ever promoted to mainstream use within the Google search engine.

Google Suggest is actually fairly sophisticated in that it dynamically displays a dropdown list from which to choose suggested search phrases. Google Suggest is interesting because it also displays the number of hits for each suggestion, thereby giving you some kind of gauge for the importance of the suggestion. What Google Suggest doesn't do is manipulate the text field itself in any way, unless of course you choose one of the suggestions from the dropdown list.

The Completer application you develop in this chapter takes a slightly different approach to the auto-complete feature than Google Suggest. To get a feel for how it will work, let's check out another handy Web site that offers auto-complete, Lyricsfly.com. Feel free to surf on over to http://www.lyricsfly.com/, which is shown in action in Figure 6.1.

Figure 6.1. Lyricsfly.com is a music lyric search engine that uses the auto-complete feature.

[View full size image]

In the figure I've clicked the Song link to search specifically for songs. Also notice in the figure the major distinction between Lyricsfly.com and Google Suggest—Lyricsfly.com actually adds the suggested text to the text field as it makes suggestions. This means you don't have to use the dropdown list if you don't want to. In fact, it means you really don't need the dropdown list at all if you don't mind continuing to type and hone in on the song. Granted, the dropdown list is a big help, and it does convey extra information such as the artists, but it isn't essential to the auto-complete feature. Figure 6.2 reveals how the dropdown list in Lyricsfly.com will eventually resolve to a single song if you continue to type the song name.

Figure 6.2. The more you type into Lyricsfly.com, the less critical the dropdown list becomes.

[View full size image]

In this figure I've entered enough of the song name to reduce the dropdown list to a single song. Of course, the whole idea is to prevent the user from having to type a lot, but you get the idea that the auto-complete feature could function reasonably well without the dropdown list.

The main point in showing how auto-complete can be implemented without a dropdown list is to set up the challenge for the Completer sample application. There is a fair amount of complexity in dynamically creating and managing a custom dropdown list, and I want to keep this example as clean as possible. You get to Ajax-driven custom popup windows later in the book, but for now I want to stick with a simple user interface without a bunch of tricky overhead code. Therefore, we'll scrap the dropdown list and create an auto-complete feature purely within a text input control.

This means the application will only be suggesting one word or phrase at any given time, but you'll see that even a single suggested phrase can go a long way toward making an application more helpful and intuitive.

So the task at hand for the Completer application is to provide an auto-complete feature solely for a text input control. In terms of how this challenge impacts Ajax, the client part of the application is responsible for sending the server the text the user is entering as each character is typed. The server takes a given piece of input text and finds the closest match in its list of possible completions (suggestions). The server then returns the remaining part of the completion to the client so that it can be added to the text input control and selected.

To make the application mildly educational, Completer uses a list of famous historical people as the basis for its auto-complete functionality. This means the user will begin by starting to enter a name, and the application will quickly (ideally) fill in the text field with its best guess as to who the person might be. If the user is happy with the suggestion, he or she doesn't need to type any more. If not, the user can elect to continue typing and the application will try again with another completion attempt. Unless the user is typing too fast for the Ajax requests to keep up, a request will be made for each individual keypress (key release, actually, but that's not the point).

In summary, the Completer application issues an Ajax request for each character entered by the user in an attempt to automatically complete the entry of a historical name. Once the name is successfully entered, the user can click a button to view a biography of the historical person on Wikipedia, the popular online encyclopedia. The Wikipedia facet of the application is just a token prize for successfully using Ajax to enter a historical name.


ch06lev1sec2.html

The Design: Designing an Auto-Complete Application

You already have a basic idea as to what is taking place in regard to the data being passed back and forth between the client and server in the Completer application, and you even know that the user interface consists primarily of a text input control. Figure 6.3 shows how the user interface factors into each Ajax request within the application.

Figure 6.3. Each character of user input results in an Ajax request that returns a completion string.

The figure shows how a single text input control serves as both the source and the destination for Ajax requests. Although this may seem unusual at first, it makes perfect sense when you consider that the text input control is playing two roles: It is both accepting input from the user and attempting to give the user information by guessing what is being typed. The key thing to note here is how the completion text in the figure is highlighted (selected), which means that if the user types another character it will overwrite the completion text. This of course triggers another Ajax request with a new response and new completion text. And so the dance continues until the user arrives at the desired input.

One interesting thing to note about the data in the Ajax request for the Completer application is how simple it is. There isn't any XML, or any data formatting at all for that matter. In fact, you're really only sending a few characters back and forth to the server at a time. Just so you understand what I mean, let's step through a quick example involving a notable figure in American history, Thomas Edison. You would start entering this name by typing a t or a T in the text box. At this point the text box contains the following:

T

Because you've entered a character, an Ajax request is immediately dispatched and the text ecumseh is returned to the text box to appear along with the T you entered:

Tecumseh

Tecumseh is the famous Shawnee Indian leader who died in the War of 1812. The name Tecumseh is initially suggested by the Completer application because Tecumseh appears before Thomas Edison alphabetically in the list of possible completions. You see this list a bit later in the chapter, but for now you can hopefully see how the alphabetic nature of the list plays into the completion process.

If you continue by typing another letter, h this time, the text ecumseh is immediately replaced by the h, giving you the following:

Th

Another Ajax request is sent out, and this time the text eodore Roosevelt is returned. Geez, are we ever going to get to Thomas Edison? Here's what the text box now holds:

Theodore Roosevelt

Clearly, Theodore Roosevelt is a step closer to Thomas Edison but still alphabetically before it, which is why this name was suggested. As it turns out, typing one more character is all it takes to finally hone in on Mr. Edison:

Tho

The server receives one more Ajax request and returns mas Edison, resulting in the following text box contents:

Thomas Edison

Now you have your name, a total of 13 characters, but you only had to type three of them. That's the power of the auto-complete feature. Hopefully this little exercise not only shines some light on the usefulness of the feature but also on the nature of the Ajax requests and responses required to carry it out.

The Client Request

The client request for the Completer application is very simple in that it sends along the user input as it is being entered in the text input control. This user input is just raw characters of text without any special formatting. In many cases, the input is just a handful of characters, although it could be more in cases where there isn't an auto-complete match and the user continues to type. Even so, you're talking about tens of characters, not hundreds of characters.

Note

Fortunately, it doesn't really matter to an Ajax request how many characters you send its way, although the more data sent the longer the request transmission will take. However, you're still talking about relatively tiny amounts of data in the grand scheme of things.

Before moving on to the server response details, it's worth addressing a concern that has been brought up regarding Ajax applications such as Completer. I'm referring to the fact that Completer is capable of issuing a flutter of requests in response to the user typing characters. Although the server-side script of Completer is simple and speedy, relying solely on data embedded in the PHP code, an application with a larger data set would likely get the completion text from a database. This means you're looking at a database hit every time the user types a character, which is potentially a problem.

The problem here is the prospect of lots and lots of database hits overwhelming a database server. This may or may not be a problem for any Ajax applications that you build using the auto-complete feature, but it's a bit of a warning to make any frequently called Ajax code extremely efficient; that is, minimal processing of minimal data. And if you should still have problems, you may need to explore a server configuration that yields better results for a high frequency of small data requests. Don't panic just yet—consider this a tiny alert to file away for future reference. Chances are you won't have any problems if you use the auto-complete feature with a little healthy restraint.

The Server Response

The server script in the Completer application is given the task of matching and returning completion text given a piece of text that has been entered by the user. Unlike many of the other applications in this book, which return data that has been carefully formatted in XML, Completer simply returns a text fragment that serves as a completion for what the user has already entered. This is just raw text with no special formatting, which means you can grab it on the client side and use it directly without parsing any XML code.

Although the server responses in the Completer application are short and sweet, they do occur much more often than Ajax responses you've seen in other applications because they are triggered every time the user types a character. This isn't necessarily a problem, but it is an argument for not using huge completion text in the list of possible completions. This list is sourced by the completer.php server script, by the way, which you see a little later in the chapter.

Making Sense of the Client-to-Server Conversation

Although you probably already have this particular client-to-server communication exchange figured out, Figure 6.4 shows exactly how the Ajax request and subsequent response relate to the browser (client) and Web server.

Figure 6.4. The Completer application involves unformatted user input and completion text flowing back and forth between the client and server.

The text data sent back and forth on each side of the Completer application is very small, typically on the order of a few characters or words. If you look back at the exchange of data earlier in the chapter for the text completion example of "Thomas Edison," you'll notice a sequence of user input characters sent out with each Ajax request. These requests are handled by the completer.php server script. Following is an example of a URL for an Ajax request that sends along the character T as the user input:

completer.php?input=T

At this point, the server responds and tries to guess that the user is entering Tecumseh, which isn't the case. If the user continues to type by entering the character h, the following URL serves as the Ajax completion request:

completer.php?input=Th

This time the text Th is being sent to the server script, which should result in a more accurate completion. The server responds by guessing Theodore Roosevelt, which is closer but not quite there. Finally, a URL with a three-character input is what it takes to get the correct completion:

completer.php?input=Tho

In this example, the server responds with the text mas Edision, which is the completion text for the name Thomas Edison (Tho + mas Edison). The user can now accept the completion and click the Learn More button to find out more about Thomas Edison. That's really all there is to the data exchange in the Completer application.


ch06lev1sec3.html

Putting Together the Completer Application

Not only is the data exchange straightforward in the Completer application, but the structure of the application is pretty simple, too, consisting of only two files:

  • HTML Web page (completer.html)

  • PHP server script (completer.php)

These two files directly correspond to the client (completer.html) and server (completer.php) portions of the application; there are no separate data sources or third-party Web services to contend with. The Completer Web page issues Ajax requests that are handled directly by the PHP server script, which then responds with data that is handled by the JavaScript code in the page.

In reality, the list of completion words and phrases, which you see in a moment as part of the completer.php code, should ideally reside in a database of some sort. Some auto-complete lists can get fairly large, and a true database is likely to be more efficient at performing searches within large data sets than straight PHP code. However, I opted for simplicity in this example and just coded the completion list as an array within the PHP server script. As long as your completion lists don't get too terribly unwieldy in size, you should be fine doing the same.

The Completer Web Page

The HTML Web page for the Completer application (completer.html) has an extremely simple user interface, consisting solely of a text input control and a button for looking up the historical name entered. Figure 6.5 shows the page open in a Web browser awaiting user input.

Figure 6.5. The Completer Web page starts out with an empty text-input box waiting for the user to enter a historical name.

[View full size image]

This user interface is primarily established by way of the body of the HTML code, which follows:

Code View:
<body onload="document.getElementById('name').value = '';
  document.getElementById('name').focus()">
  <div id="ajaxState" style="display:none"></div>
  <br />
  <div>
    Enter a historical name:
    <input id="name" type="text" size="32"
      onkeyup="getCompletion(this, event)" />
    <input id="learnButton" type="button" value="Learn More..." onclick="showBiography()" />
  </div>
</body>

This code reveals how the page consists of two input controls—one a text box and the other a button. Notice that the text box is cleared in the body's onload event handler, and focus is set to it as well. This latter action is a good idea for any Web page where the initial action is the user entering text. Google is a good example of this same strategy—the focus is always set to the search text box.

Also notice that the onkeyup event handler for the text input control is set so that it calls the getCompletion() function. This is the function responsible for initiating an Ajax request that retrieves a completion suggestion from the Web server. Here's the code for it:

function getCompletion(inputControl, evt) {
  evt = evt ? evt : (event ? event : null);
  if (evt) {
    // Ignore keys that don't factor in to the text entry
    var key = evt.charCode ? evt.charCode : evt.keyCode;
    if (key < 32 || (key >= 33 && key <= 46) ||
     (key >= 112 && key <= 123))
      return;

    // Store away the current input
    currentInput = inputControl.value;

    // Send the Ajax request to load the completion
    ajaxSendRequest("GET", "completer.php?input=" +
      encodeURIComponent(inputControl.value),
      handleCompletionRequest);
  }
}

Note

Earlier in the chapter I mentioned a potential performance problem related to Ajax requests such as this one where lots of requests are issued in response to key presses. One clever way around such a problem is to set a timer for issuing completion requests instead of issuing a request in response to every single key press. For example, you might check for a new key press twice a second, in which case the net effect is roughly the same in terms of completion text appearing but the maximum number of requests are throttled back to two per second.

Most of the initial code in this function takes care of browser inconsistencies with respect to how events are handled. In this case you are interested in getting the value of a key release, which involves a few tricks so that the code will work in any major browser. Once the character code of the key is resolved, it is checked against several ranges of keys to make sure that it is indeed valid entry text. This prevents a control key such as Shift or Enter from being interpreted as valid data entry, which would otherwise issue an Ajax auto-completion request.

If the user input is indeed valid, it is stored away in a global variable called currentInput. The server URL for the Ajax request is then assembled based upon the text in the text box, and the request is sent to the server. Notice that the handleCompletionRequest() function is responsible for answering the call when the Ajax request returns with a response. Following is the code for this function:

Code View:
function handleCompletionRequest() {
  if (request.readyState == 4 && request.status == 200) {
    // Grab the response text and kill any trailing whitespace
    var completion = request.responseText.replace(/\s*$/g, "");

    // Only issue an Ajax request if the input control still
    // has the current input
    var inputControl = document.getElementById("name");
    if (completion && (inputControl.value == currentInput)) {
      if (inputControl.setSelectionRange) {
        // Add the completion to the input control for non-IE
        // browsers
        var inputLen = inputControl.value.length;
        inputControl.value += completion;
        inputControl.setSelectionRange(inputLen,
          inputControl.value.length);
      }
      else if (inputControl.createTextRange) {
        // Add the completion to the input control for IE
        var sel = inputControl.createTextRange();
        sel.text += completion;
        sel.moveStart("character", -completion.length);
        sel.moveEnd("character", 0);
        sel.select();
      }
    }
  }
  ajaxUpdateState();
}

The handleCompletionRequest() function receives each Ajax server response, and is responsible for carefully inserting the completion text into the text box and selecting it. Although this task sounds simple enough, yet again browser incompatibilities result in two branches of code: one to accommodate IE and another to accommodate other browsers. It's unfortunate that at this stage of the Web's evolution we're still dealing with completely different approaches to something as simple as selecting text in a text box. But complaining isn't going to get this application working any sooner!

Looking back near the beginning of the handleCompletionRequest() function, you'll see a line of code that manipulates the server response text and stores it in the completion variable. This manipulation is necessary because the response text picks up some extra characters in the process of being sent from the server to the client. These characters appear at the end of the text and are likely a result of the echo command in the PHP script, even though it isn't supposed to append a line-feed, newline, or any other character to the end of a piece of text. At any rate, the standard text replace() method is used to trim excess characters off the end of the response text before proceeding.

The remainder of the handleCompletionRequest() function includes two different techniques for adding the completion text to the text box and then selecting it. Notice that before the code branches to browser-specific code, the currentInput variable is checked against the value of the text box. This is an important check because it makes sure the Ajax request matches the input that triggered it. It's possible for someone to type really fast and enter characters faster than the Ajax requests can resolve. In this case, you only want the last request to count. This piece of code helps to make sure that happens.

Although the two browser-specific code branches are different in their details, they both do the same thing:

  • Append the completion to the end of the user input in the text box.

  • Select the completion in the text box so that if the user enters another character, the completion will be automatically erased.

That wraps up the client-side functionality of the auto-complete feature, but this isn't quite the end of the Completer Web page. If you look back at the HTML code for the body of the page, a function called showBiography() is called in response to the user clicking the Learn More button. Here's the code for this function:

function showBiography() {
  // Open a link in Wikipedia based upon the historical name
  // entered
  if (document.getElementById("name").value != "")
    window.location = "http://en.wikipedia.org/wiki/" +
      encodeURIComponent(document.getElementById("name").value);
}

The idea here is to make the application do something meaningful with the historical name that has been entered. So the showBiography() function takes the historical name (contents of the text box) and uses it to build a URL for the Wikipedia online encyclopedia. This URL takes the following form: http://en.wikipedia.org/wiki/Thomas_Edison

In this example, the name Thomas Edison is simply grafted onto the end of a boilerplate URL, which you can see in the code for the showBiography() function. The URL is then opened in the current browser instance by assigning it to the window.location property, which is akin to typing in the address bar of the browser. In other words, when you set the window.location property to a certain URL, it forces the browser to navigate to that URL.

The Completer Server Script

The server side of the Completer application involves a PHP server script named completer.php. This script is not only responsible for receiving a request and responding with a completion, but also serves as the data repository for the list of possible completions. I mentioned earlier in the chapter that this list might be better off stored in a true database, especially for applications that utilize large completion lists, but for the sake of simplicity the list works fine in the PHP script for this application.

Following is the abbreviated code for the completer.php server script:

Code View:
<?php
$people = array(
  "Abraham Lincoln",
  "Adam Smith",
  "Adolf Hitler",
  "Albert Einstein",
  "Alexander Fleming",
  "Alexander Graham Bell",
  "Alexander Hamilton",
  "Alexander the Great",
  "Alfred T. Mahan",
...
  "William Harvey",
  "William Shakespeare",
  "William T.G. Morton",
  "William the Conqueror",
  "Willis Haviland Carrier",
  "Woodrow Wilson",
  "Ziryab"
);
$input = strtolower($_GET['input']);
$inputLen = strlen($input);

if ($inputLen > 0) {
  for ($i = 0; $i < count($people); $i++) {
    if (strtolower(substr($people[$i], 0, $inputLen)) ==
      $input) {
      echo substr($people[$i], $inputLen,
        strlen($people[$i]) - $inputLen);
      break;
    }
  }
}
?>

The most significant code in this script is the array of historical people, which is laid out as a list of alphabetized names in quotes. Notice that each name is separated by a comma, and that the entire list is enclosed within parentheses. This is standard formatting for arrays in PHP, and I point it out so that you know to maintain the format when modifying the completion list or creating one of your own.

One subtle detail of the Completer application that I haven't mentioned yet is how it doesn't care about the case of the user input. In other words, it will match Thomas Edison if you enter, tho, Tho, or tHo. The code responsible for this is the first line below the completion list that calls the standard strtolower() function.

The remaining code in the server script takes on the task of searching through the completion list one name at a time, looking for a match with the input text. If a match is found, it is echoed to the client, and the script ends. This is an important detail that reveals why the completion list must be in alphabetical order—the first match of the input text is always the one returned. Because the first match always wins, the only way to get consistent results is to alphabetize the list. A bit later in the chapter I offer a little trick where you can use Microsoft Word to automatically alphabetize a list—this can be very helpful if you have a huge list that isn't in any order.

You now have the two pieces of the application put together, so it's time to move on to the most fun development phase, testing!


ch06lev1sec4.html

Testing Completer

The Completer application is pretty simple when it comes to testing, seeing as how all you have to do is start typing and see what happens. Figure 6.6 shows the application after the character C is entered in the text box.

Figure 6.6. Entering a single character in the text box of the Completer application results in an attempted completion.

[View full size image]

The first historical person found whose name begins with C is Charlemagne, which is evident in the figure. Because the completion text is automatically selected, you can continue typing if that name isn't the correct match. Continue by typing the character o, which results in a different name, as you might expect (see Figure 6.7).

Figure 6.7. As you continue typing characters, the application continues to find the best match for the completion.

[View full size image]

Ah, Confucius says this is the name I want, so I'm going to stop typing and click the Learn More button to find out more about the Chinese philosopher.

A simple click of a button leads you to a wealth of information about the person whose name you entered with the help of the auto-correct feature. The Wikipedia facet of the Completer application certainly isn't critical in any way, but it does add a touch of practical sizzle.


ch06lev1sec5.html

Giving Completer an Extreme Ajax Makeover

The Completer application is one of the most broadly applicable examples in this book because it can be applied to virtually any text input, provided that it is somehow possible to predict what the user might type. As you think about using the auto-complete feature in your own pages, the key is to isolate text input that is predictable enough to be modeled with a list of words or phrases, but also not so predictable that a selection list would better serve your purposes.

As an example of where auto-complete might be overkill, consider the example of helping the user type in a state in the United States. Because there is a finite and relatively small list of states, it probably makes more sense to just have the user select from a list of states. On the other hand, maybe you want to use auto-complete to assist someone in entering the name of their pet. Although this might ultimately be a viable application of auto-complete, the list of possible names is so huge and open-ended that it may not be worth trying to help. The point is that auto-complete is certainly an extremely useful user input tool, but you should make sure to think through the specific type of input before assuming that it makes sense to use auto-complete.

With that little rant out of the way, let me say that the first thing you should try to do with the Completer application is change out the completion list entirely. Think of some other text-entry scenario that would be cool to assist the user with. Then change the data set in the completer.php server script; just make sure that the list remains in alphabetical order. The application will immediately start trying to auto-complete the text input using your new list of completions.

Tip

If you're building a list of words and/or phrases for the Completer application and they aren't already in alphabetical order, I have a little trick to save you some time and energy. You need access to Microsoft Word, but that shouldn't be too terribly difficult considering how prevalent Microsoft Office is these days. Create a new document in Word, and then copy and paste your list of completions into it. Select all of the completions, and then click Table on the Word menu. Then select Sort from the Table menu. A dialog box will appear. Make sure the Ascending radio box is selected, and then click OK. Presto! Your list is now alphabetized.

Another practical possibility for applying the Completer application to your own Web site is adding a context-sensitive search box to your site. For example, let's say you run a Web site devoted to extreme sports. You could offer a search box that uses auto-complete to suggest extreme sports terms and people. You already know how to help the user enter text into a text control via auto-complete, so all you're missing is the trick to route the input text to Google and perform the search.

Initiating a Google search is as easy as redirecting your Web page to a Google URL that includes the search string. Following is an example of such a Google URL: http://www.google.com/search?q=tony+hawk

This sample URL searches for the text "tony hawk", which would find tons of matches for professional skateboarder Tony Hawk. Notice that a plus sign (+) is used to separate the first and last name. You must use + in place of any spaces in the search terms.

Your remaining task is to redirect the page to the Google URL. Assuming the text input control in your application still has the ID name, as in the Completer application, the following code grabs the input text, converts its spaces to plus signs (+), builds a Google search URL, and redirects the browser to it:

var searchText = document.getElementById("name").value.replace(  " ", "+");
window.location = "http://www.google.com/search?q=" + searchText;

That's all the code you need to convert an auto-completed context-sensitive text field entry into a Google search.


ch06lev1sec6.html

Summary

This chapter added an extremely handy Ajax technique to your rapidly expanding bag of tricks. The Completer application is very focused and simple in that it only applies to a text control, but when used properly it yields surprisingly effective results in the usability of a Web page. The fact that you can completely ignore the auto-complete suggestion and continue typing means that the feature doesn't get in the way if the completion suggestions happen not to help. This is a common aspect of many Ajax techniques, and a point you should always keep in mind when injecting Ajax into your own pages.


ch07.html

Chapter 7. Creating Responsive GUIs with Real-Time Validation

Ajax the Cleanser

You knew it was coming sooner or later, so why wait any longer? Perhaps the most known usage of the term Ajax is the all-purpose cleanser that was introduced by Colgate-Palmolive in 1947. The cleanser was named after the powerful Greek hero Ajax, which led to the Ajax product slogan: "Stronger than dirt!"

One of the truly killer applications of Ajax is real-time user input validation, which means that data entered by the user is checked for validity as the user enters it. This can dramatically improve the efficiency of user interfaces because errors are caught as they are made, thus eliminating the need to submit an entire form to find out whether a problem exists. Additionally, applications just feel smarter when they give immediate feedback to the user regarding data entry. As it turns out, Ajax isn't technically required for a lot of real-time validation tricks, but it still does play a role in some instances when it is necessary to load data from a server as part of the validation.

This chapter digs into real-time validation and explores when and where it makes sense to inject such functionality into your own applications. You also take a quick break from Ajax to learn how to validate popular data types such as phone numbers, dates, and email addresses. Ajax then comes back into play as you work through a practical example involving ZIP code validation that performs a live look-up of the respective city and state. This is an extremely handy Ajax trick you can use to significantly streamline the entry of location/address information.

The following files are used by the Validator application in this chapter and are located on the live Linux CD-ROM with the book in the chap07 example code folder:

  • validator.html—Main Web page

  • ziplookup.php—Server script for looking up a city/state based upon a ZIP code

  • ajaxkit.js—Core Ajax functions for the Ajax Toolkit

  • domkit.js—DOM-related functions for the Ajax Toolkit

  • validatekit.js—Validation functions for the Ajax Toolkit

  • wait.gif—Animated "loading" icon that is displayed during an Ajax request

The Challenge: Checking User Input in Real Time

The challenge laid down in this chapter is quite broad—improve the retrieval of information from the user by eliminating input errors immediately at the point where they are made. If you use a word processor such as Microsoft Word, which has a real-time spell checker, then you understand how handy this feature can be. In many ways the auto-completion application in the previous chapter can be thought of as roughly similar to a real-time validator. However, auto-complete is more about improving efficiency than it is about correcting mistakes, even though the two tasks often go hand in hand.

To see a practical validator in action, check out Google's Gmail online email service at http://mail.google.com/. The invitation feature in Gmail allows you to send an invitation to a friend to join Gmail. The invitation request requires the email address of your friend, which is what you're supposed to enter in the text box. An improperly formatted email address results in Gmail displaying an "invalid address" message just below the email address text box.

Gmail isn't quite as aggressive with its validation as some Ajax applications, which is evident by the fact that you have to click a Send Invite button before Gmail performs the validation. A more aggressive approach would involve validating the address as soon as the user leaves the email text box. This latter approach is often employed in Ajax applications, and in most cases serves as an improvement because it can head off invalid data entry as soon as it is entered.

The general idea behind a modern approach to user input validation is to eliminate the need for a page reload in order to see if data is valid. In many cases you can eliminate the entire trip to the server and perform the validation entirely within the client. Strictly speaking, if the server isn't involved, the validation isn't truly using Ajax. However, there is a notion of an Ajax "feel" to an application that can still be gained via client-side validation. The challenge in this chapter involves both client-only and true Ajax validation.

Speaking of the challenge, this chapter gets away from accomplishing a central task and instead focuses on demonstrating how to validate several different kinds of user input. Sure, it would've been possible to dream up some example involving numbers, dates, email addresses, phone numbers, and ZIP codes, but the additional overhead would just distract from the real emphasis, validating data. So the challenge in the Validator application is to simply present several user-input text boxes, each associated with a particular data type, and validate each one in real time as the user moves through the user interface.

Following are the data types targeted for validation by the Validator application:

  • Integer

  • Number

  • Phone number

  • Email address

  • Date

  • ZIP code

The key to validation isn't just popping up an annoying alert box to let the user know his or her input is bad. In fact, an alert box is the worst way you can go about notifying the user of an input problem. A better approach is to sneakily provide help fields on the form that are invisible unless a validation problem occurs, in which case you display help text for the user. For example, you might display the help text

"Please enter a date (for example, 01/14/1975)."

when the user enters an invalid date. The help text appears when the data is bad and then magically goes away once the data is fixed.

Of course, the "magic" is in the validation code that supports the help text feature. This code is part of the validatekit.js file included as part of the Ajax Toolkit on the CD-ROM with this book, and is also a part of the source code files for the Validator sample application. As was originally mentioned back in Chapter 2, "Inside an Ajax Application," the validatekit.js file offers several JavaScript functions you can use to validate different types of data. More specifically, the validatekit.js file exposes the following JavaScript functions that can be used for validating user input data:

  • validateNonEmpty()—Is the data empty?

  • validateInteger()—Is the data a valid integer?

  • validateNumber()—Is the data a valid number?

  • validateZipCode()—Is the data a valid ZIP code?

  • validatePhone()—Is the data a valid phone number?

  • validateEmail()—Is the data a valid email address?

  • validateDate()—Is the data a valid date?

As you can see, these functions just so happen to match up perfectly with the data types targeted by the Validator application. This means that the challenge just got a whole lot easier because you now have standard JavaScript functions you can use to validate each data type. The challenge primarily becomes figuring out how to wire these functions into the HTML elements on the Validator page so that data within text boxes is properly routed to the JavaScript functions. Also, you'll need to create HTML elements for displaying the help text for each text box so that the validation functions can display help text.

At this point you may be wondering exactly where Ajax fits into the Validator equation, and the answer is that it doesn't... at least not yet. All of the data types targeted by the application can be validated perfectly fine within the client without any assistance from a server. Or at least the format of the data can be validated on the client. ZIP code data is a little unusual because you can validate the format of a ZIP code (exactly five integer numbers, for example) on the client but you won't know if the ZIP code is truly valid in the real world. In other words, is the ZIP code actually in use?

The only way to check for the validity of a ZIP code is to look it up in a database of real ZIP codes to see if it is indeed real. This database would be able to tell you that 90210 is indeed a real ZIP code and that it represents Beverly Hills, CA. As it turns out, such databases already exist and can be accessed via Ajax requests. Even better, most of them can provide you the data in an XML format, making it easy to sort out in your Ajax code. Ajax therefore enters the picture with the Validator application by way of looking up the city and state for a ZIP code to verify that the ZIP code is real.

So now you have a fairly complete validation challenge involving several client-side data validations as well as a true Ajax validation involving ZIP codes and their respective cities and states. You can now turn your attention to the design of the Validator application.


ch07lev1sec1.html

Chapter 7. Creating Responsive GUIs with Real-Time Validation

Ajax the Cleanser

You knew it was coming sooner or later, so why wait any longer? Perhaps the most known usage of the term Ajax is the all-purpose cleanser that was introduced by Colgate-Palmolive in 1947. The cleanser was named after the powerful Greek hero Ajax, which led to the Ajax product slogan: "Stronger than dirt!"

One of the truly killer applications of Ajax is real-time user input validation, which means that data entered by the user is checked for validity as the user enters it. This can dramatically improve the efficiency of user interfaces because errors are caught as they are made, thus eliminating the need to submit an entire form to find out whether a problem exists. Additionally, applications just feel smarter when they give immediate feedback to the user regarding data entry. As it turns out, Ajax isn't technically required for a lot of real-time validation tricks, but it still does play a role in some instances when it is necessary to load data from a server as part of the validation.

This chapter digs into real-time validation and explores when and where it makes sense to inject such functionality into your own applications. You also take a quick break from Ajax to learn how to validate popular data types such as phone numbers, dates, and email addresses. Ajax then comes back into play as you work through a practical example involving ZIP code validation that performs a live look-up of the respective city and state. This is an extremely handy Ajax trick you can use to significantly streamline the entry of location/address information.

The following files are used by the Validator application in this chapter and are located on the live Linux CD-ROM with the book in the chap07 example code folder:

  • validator.html—Main Web page

  • ziplookup.php—Server script for looking up a city/state based upon a ZIP code

  • ajaxkit.js—Core Ajax functions for the Ajax Toolkit

  • domkit.js—DOM-related functions for the Ajax Toolkit

  • validatekit.js—Validation functions for the Ajax Toolkit

  • wait.gif—Animated "loading" icon that is displayed during an Ajax request

The Challenge: Checking User Input in Real Time

The challenge laid down in this chapter is quite broad—improve the retrieval of information from the user by eliminating input errors immediately at the point where they are made. If you use a word processor such as Microsoft Word, which has a real-time spell checker, then you understand how handy this feature can be. In many ways the auto-completion application in the previous chapter can be thought of as roughly similar to a real-time validator. However, auto-complete is more about improving efficiency than it is about correcting mistakes, even though the two tasks often go hand in hand.

To see a practical validator in action, check out Google's Gmail online email service at http://mail.google.com/. The invitation feature in Gmail allows you to send an invitation to a friend to join Gmail. The invitation request requires the email address of your friend, which is what you're supposed to enter in the text box. An improperly formatted email address results in Gmail displaying an "invalid address" message just below the email address text box.

Gmail isn't quite as aggressive with its validation as some Ajax applications, which is evident by the fact that you have to click a Send Invite button before Gmail performs the validation. A more aggressive approach would involve validating the address as soon as the user leaves the email text box. This latter approach is often employed in Ajax applications, and in most cases serves as an improvement because it can head off invalid data entry as soon as it is entered.

The general idea behind a modern approach to user input validation is to eliminate the need for a page reload in order to see if data is valid. In many cases you can eliminate the entire trip to the server and perform the validation entirely within the client. Strictly speaking, if the server isn't involved, the validation isn't truly using Ajax. However, there is a notion of an Ajax "feel" to an application that can still be gained via client-side validation. The challenge in this chapter involves both client-only and true Ajax validation.

Speaking of the challenge, this chapter gets away from accomplishing a central task and instead focuses on demonstrating how to validate several different kinds of user input. Sure, it would've been possible to dream up some example involving numbers, dates, email addresses, phone numbers, and ZIP codes, but the additional overhead would just distract from the real emphasis, validating data. So the challenge in the Validator application is to simply present several user-input text boxes, each associated with a particular data type, and validate each one in real time as the user moves through the user interface.

Following are the data types targeted for validation by the Validator application:

  • Integer

  • Number

  • Phone number

  • Email address

  • Date

  • ZIP code

The key to validation isn't just popping up an annoying alert box to let the user know his or her input is bad. In fact, an alert box is the worst way you can go about notifying the user of an input problem. A better approach is to sneakily provide help fields on the form that are invisible unless a validation problem occurs, in which case you display help text for the user. For example, you might display the help text

"Please enter a date (for example, 01/14/1975)."

when the user enters an invalid date. The help text appears when the data is bad and then magically goes away once the data is fixed.

Of course, the "magic" is in the validation code that supports the help text feature. This code is part of the validatekit.js file included as part of the Ajax Toolkit on the CD-ROM with this book, and is also a part of the source code files for the Validator sample application. As was originally mentioned back in Chapter 2, "Inside an Ajax Application," the validatekit.js file offers several JavaScript functions you can use to validate different types of data. More specifically, the validatekit.js file exposes the following JavaScript functions that can be used for validating user input data:

  • validateNonEmpty()—Is the data empty?

  • validateInteger()—Is the data a valid integer?

  • validateNumber()—Is the data a valid number?

  • validateZipCode()—Is the data a valid ZIP code?

  • validatePhone()—Is the data a valid phone number?

  • validateEmail()—Is the data a valid email address?

  • validateDate()—Is the data a valid date?

As you can see, these functions just so happen to match up perfectly with the data types targeted by the Validator application. This means that the challenge just got a whole lot easier because you now have standard JavaScript functions you can use to validate each data type. The challenge primarily becomes figuring out how to wire these functions into the HTML elements on the Validator page so that data within text boxes is properly routed to the JavaScript functions. Also, you'll need to create HTML elements for displaying the help text for each text box so that the validation functions can display help text.

At this point you may be wondering exactly where Ajax fits into the Validator equation, and the answer is that it doesn't... at least not yet. All of the data types targeted by the application can be validated perfectly fine within the client without any assistance from a server. Or at least the format of the data can be validated on the client. ZIP code data is a little unusual because you can validate the format of a ZIP code (exactly five integer numbers, for example) on the client but you won't know if the ZIP code is truly valid in the real world. In other words, is the ZIP code actually in use?

The only way to check for the validity of a ZIP code is to look it up in a database of real ZIP codes to see if it is indeed real. This database would be able to tell you that 90210 is indeed a real ZIP code and that it represents Beverly Hills, CA. As it turns out, such databases already exist and can be accessed via Ajax requests. Even better, most of them can provide you the data in an XML format, making it easy to sort out in your Ajax code. Ajax therefore enters the picture with the Validator application by way of looking up the city and state for a ZIP code to verify that the ZIP code is real.

So now you have a fairly complete validation challenge involving several client-side data validations as well as a true Ajax validation involving ZIP codes and their respective cities and states. You can now turn your attention to the design of the Validator application.


ch07lev1sec2.html

The Design: Designing a Validator Application

The design of the Validator application is hopefully a little more obvious than some of the other applications in the book, primarily because discrete pieces of user input data are validated independently of one another. Your design job is basically just to call the appropriate validatekit.js validation function for each user-input text box. Then there is the Ajax request that provides an additional level of validation for ZIP codes by looking up the city and state from a Web service.

Figure 7.1 shows a rough interpretation of the user interface for the application, which reveals how the help fields are arranged next to each input text box.

Figure 7.1. The user interface for the Validator application consists of several text boxes and their associated help text fields.

You can see in the figure how each text box is associated with a particular kind of data, such as a phone number, an email address, etc. The help field next to each text box is used to convey help information about the validity of the data in that text box. The only exception is the help field for the ZIP code, which serves double duty as a display field for the city and state retrieved via an Ajax request.

Speaking of the Ajax request for the ZIP field, it would be quite handy to display an animated "loading" image to let the user know that the application is busy looking up the city and state based upon the ZIP code. This image, wait.gif, is shown in Figure 7.2.

Figure 7.2. The Validator application makes use of an animated "loading" image (wait.gif) to let the user know the Ajax request is being processed.

The "loading" image is displayed in the same field that holds the help text for the ZIP code, which I suppose makes the field actually perform triple duty. The following three pieces of information are capable of appearing in the ZIP code's help field at different times throughout the process of entering a ZIP code:

  • Help text is shown when the ZIP code is invalid.

  • The "loading" image is shown while an Ajax request is being carried out.

  • The dynamically loaded city and state are shown after a successful Ajax request.

This may seem like a lot of stuff is going on with respect to the ZIP code and its helper field, but the Validator application handles it all without much complication. Keep in mind that the application is really only dealing with one Ajax request, which also helps to simplify things. You're now ready to learn a little more about the ZIP code Ajax request.

The Client Request

The client request for the Validator application is very basic in that it sends along the ZIP code when the ZIP code text-input control loses focus. This approach is very different from the Completer application in Chapter 6, "Reading the User's Mind with Auto-Complete," which issues an Ajax request after each individual character is typed. The character-by-character request technique doesn't make sense for Validator because it takes multiple keypresses to enter a meaningful piece of data in Validator—you must wait until the user is finished entering the data before attempting a validation. Your cue that the user is finished entering data in the ZIP code input control is when he or she leaves the control by tabbing away from it or clicking off of it.

Once the user has left the ZIP code text box, you're free to send along the input as part of an Ajax request. This user input is just raw characters of text without any special formatting. The integer validation that has already been performed does ensure that the ZIP code text consists of five integer characters, but the text is still considered unformatted in a sense that it isn't encoded in XML or any other standard data format.

Note

I realize there is a longer ZIP code format of the form #####-#### that could feasibly enter the picture here. To keep things simple, I've opted to stick with the basic five-digit ZIP code, which has the form #####.

That's all you need to know about the minimal amount of data sent from the client to the server for a ZIP code lookup. Let's now address what the server sends back.

The Server Response

The Ajax server response in the Validator application returns information about the ZIP code sent over in the request. This response is indirectly received from a third party Web service, webserviceX.net, that offers several handy data feeds in XML format. In this case, the webserviceX.net service uses a ZIP code to look up and return a matching city, state, area code, and time zone. Since all you need in the Validator application is the city and state, you can ignore the area code and time zone. The fact that the response data is formatted as XML code makes it easy to access only the specific data you need.

You may recall from some of the earlier applications that you can't make an Ajax request on a third-party domain. Therefore, the trick is to alleviate this security limitation by making the third-party data request from a server script, and then using Ajax to get the data from that script, which resides on your server. This works because there isn't a security issue with requesting data from a server script. So the Validator application needs to include a PHP server script that serves as a proxy for making ZIP code requests to the webserviceX.net service.

Making Sense of the Client-to-Server Conversation

The Ajax request within the Validator application is used to shuttle a user-entered ZIP code to the server and then receive a city and state in return. Figure 7.3 helps to clarify this transfer of data visually.

Figure 7.3. The Validator application involves an unformatted ZIP code and formatted city and state data flowing back and forth between the client and server.

The data sent to the server as a parameter of the Ajax request is a ZIP code that has been entered by the user. The ZIP code has already been validated in terms of its format but has not been checked to make sure it really matches up with a city and state. ZIP code requests are handled by the ziplookup.php server script. Following is an example of an Ajax request URL that sends along the ZIP code 85250 as the only parameter to the server script:

ziplookup.php?zipCode=85250

This code reveals how the ZIP code is packaged into a URL as a single parameter (zipCode). This entire URL is used as the basis for an Ajax request, in which case your server script, ziplookup.php, will take the zipCode parameter and use the URL it contains to obtain the city and state information.

The city and state data is returned as a compact XML document that actually contains the city, state, area code, and time zone for the ZIP code, assuming the ZIP code is successfully matched. Following is an example of what such an XML document actually looks like:

<NewDataSet>
  <Table>
    <CITY>Scottsdale</CITY>
    <STATE>AZ</STATE>
    <ZIP>85250</ZIP>
    <AREA_CODE>602</AREA_CODE>
    <TIME_ZONE>M</TIME_ZONE>
  </Table>
</NewDataSet>

Even if you aren't an XML guru, this code isn't too terribly hard to figure out. You're really only interested in the <CITY> and <STATE> tags because they contain the city and state for the ZIP code. The remaining task is then to extract the city and state from this data on the client.


ch07lev1sec3.html

Putting Together the Validator Application

Aside from the standard toolkit JavaScript files, including validatekit.js, the Validator application consists of only two components:

  • HTML Web page (validator.html)

  • PHP server script (ziplookup.php)

Of course, the other major ingredient in the application is the third party location Web service that is responsible for providing the city/state data based upon a ZIP code. Although this service is an important part of the application, it doesn't require a distinct component other than code within the HTML Web page that initiates an Ajax request and code within the PHP server script that handles relaying the response back to the page. This arrangement is necessary because Ajax requests aren't allowed direct access to resources located on other domains.

The next couple of sections explore the Validator Web page and server script in detail in order to fully understand how the application works.

The Validator Web Page

The HTML Web page for the Validator application, validator.html, consists of a series of text box input fields, each with a non-input text field next to it that serves as a display area for help messages. The text boxes are created as input elements, while the help message fields are created as span elements. Figure 7.4 shows the Validator application open in a Web browser with the blank text fields ready for user input and all of the help messages indicating that the fields are missing data.

Figure 7.4. The Validator Web page consists of a series of text box input controls followed by text display areas.

[View full size image]

Note

The application doesn't automatically display help messages initially as shown in the figure. Instead, the "Please enter a value." help message doesn't appear until you actually navigate away from an input control without entering anything.

With the layout of the Validator application in mind, as revealed in the figure, check out the HTML code for the body of the Web page:

Code View:
<body onload="document.getElementById('something').focus()">
  <div id="ajaxState" style="display:none; font-style:italic">
  </div>
  <br />
  <div>
    Enter something:
    <input id="something" type="text" size="32" onblur=
      "validateNonEmpty(this,
document.getElementById('something_help'))" />
    <span id="something_help" class="help"></span>
  </div>
  <div>
    Enter an integer:
    <input id="integer" type="text" size="32" onblur=
      "validateInteger(this,
      document.getElementById('integer_help'))" />
    <span id="integer_help" class="help"></span>
  </div>
  <div>
    Enter a number:
    <input id="number" type="text" size="32" onblur=
      "validateNumber(this,
      document.getElementById('number_help'))" />
    <span id="number_help" class="help"></span>
  </div>
  <div>
    Enter a phone number:
    <input id="phone" type="text" size="32" onblur=
      "validatePhone(this,
      document.getElementById('phone_help'))" />
    <span id="phone_help" class="help"></span>
  </div>
  <div>
    Enter an email address:
    <input id="email" type="text" size="32" onblur=
      "validateEmail(this,
      document.getElementById('email_help'))" />
    <span id="email_help" class="help"></span>
  </div>
  <div>
    Enter a date:
    <input id="date" type="text" size="32" onblur=
      "validateDate(this,
      document.getElementById('date_help'))" />
    <span id="date_help" class="help"></span>
  </div>
  <div>
    Enter a ZIP code:
    <input id="zipcode" type="text" size="16"
      onblur="if (validateZipCode(this,
        document.getElementById('zipcode_help')))
        getCityState(this.value);" />
    <span id="zipcode_help" class="help"></span>
  </div>
</body>

After the focus is set to the first text box on the page via the onload event handler, the body of the page moves on to creating each of the text box input and associated help message span pairs. There isn't much particularly unusual about any of this code except for the onblur event handler, which gets called when the input focus leaves an input control. So, when the user tabs away from a text box or clicks somewhere else on the page, the text box receives an onblur event notification. This is where you call a function to validate the input value in the text box.

The functions that take care of the validating in the Validator application are all part of the validatekit.js Ajax Toolkit file, which must be imported into the Web page with the following line of code (placed in the head of the page):

<script type="text/javascript" src="validatekit.js"> </script>

Each of the functions provided by this file accept the same two function parameters:

  • The input control containing the value to be validated

  • The help control used to display help text

To see how these parameters get passed into a validation function, take a look at the code that calls the integer validation function:

validateInteger(this, document.getElementById('integer_help'))

Because the function is called from within the context of the integer text box, you can pass this as the first parameter to the function. The second parameter is then specified using the standard getElementById() function to grab the integer help control, whose ID is integer_help.

If you pay close attention to the help controls on the page, you may notice that each of the span elements is styled to a CSS style class named help. This style class simply changes the color of the font to red (#FF0000) and the style of the font to italic, which makes the help messages jump out a little more on the page. Following is the code for the Validator Web page's internal style sheet, which includes the span.help style class:

<style type="text/css">
  div { padding-bottom:5px; }
  span.help { color:#AA0000; font-style:italic; }
</style>

A global div style is included in the style sheet purely to help provide a bit of vertical spacing between the input controls on the page.

Although the Validator internal style sheet is helpful in making the page look a little better, it doesn't do much to help on the Ajax front. The code that initiates Ajax requests for the Validator application is contained in the onblur event handler for the ZIP code text box. Although this code is in the listing you just saw, it's easier to follow if you break it out of the onblur attribute:

if (validateZipCode(this,
  document.getElementById('zipcode_help')))
  getCityState(this.value);

This code first validates the ZIP code input data to see if it is indeed a five-digit number. This is accomplished with the call to the validateZipCode() function. The return value of the function indicates whether the data is valid (true) or invalid (false). If the data is valid, the getCityState() function is called to initiate an Ajax request. Here's the code for this function:

function getCityState(zipCode) {
  // Display the wait image
  document.getElementById("zipcode_help").innerHTML =
    "<img src='wait.gif'
    alt='Looking up ZIP code...' />";

  // Send the Ajax request to load the city/state
  ajaxSendRequest("GET", "ziplookup.php?zipCode=" + zipCode,
    handleCityStateRequest);
}

Ah, you finally see some of the magic that makes this application look cool. The first task in the getCityState() function is to display the animated "loading" image, wait.gif, in the ZIP code help control. This image will remain displayed until the Ajax request is completed, thereby giving the user a visual cue that something is taking place behind the scenes.

The second task in the getCityState() function is to actually submit the Ajax request, which involves packaging the ZIP code into a URL for the ziplookup.php server script. The handleCityStateRequest() function is specified as the request handler for the ZIP code Ajax request. Here's the code for it:

function handleCityStateRequest() {
  if (request.readyState == 4 && request.status == 200) {
    // Store the XML response data
    var xmlData = request.responseXML;

    // Display the city/state results
    if (xmlData != null &&
      getText(xmlData.getElementsByTagName("CITY")[0]) != "")
      document.getElementById("zipcode_help").innerHTML =
        "<span style='font-weight:bold'>" +
        getText(xmlData.getElementsByTagName("CITY")[0]) +
        ", " +
        getText(xmlData.getElementsByTagName("STATE")[0]) +
        "</span>";
    else
      document.getElementById("zipcode_help").innerHTML =
        "Could not find the ZIP code.";
  }
  ajaxUpdateState();
}

The job of this function, which is called when the Ajax request completes, is to extract the city and state from the response data and display them on the page in place of the "loading" image. The city/state data is extracted with a little help from the getText() Ajax Toolkit function, which is located in the domkit.js file. Notice that the XML element names CITY and STATE are used as the basis for accessing the city and state data. Not only is this data extracted, but it is carefully reformatted using HTML code constructed on the fly. If all goes well, the resulting HTML code looks something like this:

<span style='font-weight:bold'>Scottsdale, AZ</span>

Notice that an inline style is applied to the city and state so that they appear in a bold font, which helps to make them distinguishable from normal help text. If there is a problem with the XML data returned from the server, a help message is displayed indicating that the ZIP code could not be found.

That wraps up the code for the Validator Web page. All that's left is to take a quick look at the PHP server script responsible for passing along the ZIP code request to a remote server.

The ZIP Lookup Server Script

Similar to the Picker application from Chapter 4, "Using Ajax to Dynamically Populate Lists: A Stock Picker," Validator requires a script on the server side to sidestep the limitation of not being able to make a direct Ajax client request on a third-party domain. The third-party domain is important because the Validator application relies on it for looking up ZIP codes. The Validator PHP script serves as somewhat of a security proxy by accepting an Ajax request on behalf of the client, retrieving the city/state data from the third-party server, and then responding to the client with the data. In this way, the Ajax request itself is made on your own domain, which is perfectly acceptable given the security constraints of Ajax.

The third-party Web service I'm talking about is webserviceX.net, which offers several XML-based data feeds. The Picker application in Chapter 4 uses this service to obtain live stock quotes, whereas Validator uses it to obtain detailed information about a ZIP code. In this case you specify a ZIP code, and the server responds with an XML document containing detailed information about it, including the city and state associated with it. You've already seen the code within this XML document, but you haven't seen the PHP script that makes it possible to receive the code via an Ajax request. Following is the code for the ziplookup.php server script:

<?php
header('Content-Type: text/xml');

// Load the XML location data from the server
$xml = html_entity_decode(file_get_contents(
  "http://www.webservicex.net/uszip.asmx/GetInfoByZIP?USZip=" .
  $_REQUEST['zipCode']));

// Return the XML location data
echo $xml;
?>

Keep in mind that the job of this script is to retrieve an XML document from the ZIP code Web service at webserviceX.net, and then simply pass that data along to the client without any modifications. It is then up to the client to do something useful with the XML code, such as display the city and state on the page.

The server script begins by making sure that the response gets treated as XML. It then loads the XML document from the ZIP code Web service, making sure to pass along the zipCode parameter so that the Web service knows which ZIP code to look up. The script concludes by returning the XML data from the script, which serves as the response to the Ajax ZIP code request.

Although I'm sure you're itching to test out the application, let's take a second to test the PHP script by itself. You saw how this is done in earlier chapters by opening PHP scripts directly in a browser—here's a sample URL for testing the ZIPLookUp script:

http://www.yourdomain.com/ziplookup.php?zipCode=94965

Assuming the ziplookup.php file is stored on your server, change the domain to match yours in this line of code and then enter the URL into your Web browser. Figure 7.5 shows the XML response data generated by the PHP script.

Figure 7.5. You can examine the XML ZIP code information returned by the ZIPLookUp PHP script by opening the script directly in a browser.

[View full size image]

It's definitely worth experimenting with the ZIP codes passed into the script via the URL to see how they impact the XML data that is returned. You should always test PHP scripts directly in this manner to make sure their results are consistent with what you expected—it's much tougher to diagnose server script problems when all you're looking at is the client Web page.


ch07lev1sec4.html

Testing Validator

The Validator application presents an interesting testing opportunity because you have several different data fields to tinker with as you check the effectiveness of the validation. You'll notice that the data types tend to progress in complexity as you move down the page. It's easy to generate a help message by either entering nothing or entering invalid data into any of the input controls, and then tabbing off of the control. Figure 7.6 shows a help message being displayed next to invalid integer data.

Figure 7.6. Entering invalid data and then leaving an input control results in the display of a help message next to the control.

[View full size image]

Of course, the text "more data" doesn't exactly constitute a valid integer, which explains the help message in the figure.

Things get more interesting as you experiment with entering data into more complex types, such as the date input control. Figure 7.7 shows an invalid date message displayed in response to a nearly valid date.

Figure 7.7. The date input control is pretty good at detecting bad dates.

[View full size image]

Obviously the month of January only has 31 days, so a date involving the 32nd day of the month is invalid in this example. The Validator application catches the input error and displays a help message.

Although date validation is handy, the most intriguing part of the Validator application is the lookup of ZIP codes, which takes place when you enter a ZIP code into the ZIP code input control and then leave the control. Figure 7.8 shows the animated "loading" image displayed as the ZIP code Ajax request is being carried out.

Figure 7.8. The "loading" image is displayed in lieu of a help message to let the user know that the ZIP code is being looked up.

[View full size image]

Yeah, I know, I couldn't resist using the most popular ZIP code on Earth to test out the application. If the ZIP code data is successfully retrieved via the Ajax request, the resulting city and state are displayed in place of the "loading" image, as shown in Figure 7.9.

Figure 7.9. A successful ZIP code Ajax request results in the display of the associated city and state next to the input control.

[View full size image]

Success is great, but what happens when a ZIP code isn't found? If you recall in the code for the application, a help message is displayed to indicate this. Figure 7.10 shows the help message displayed in response to a ZIP code that isn't associated with a real city and state.

Figure 7.10. A ZIP code with no real-world city and state results in a help message indicating that the ZIP code couldn't be found.

[View full size image]

It's important to note that a ZIP code that isn't found isn't necessarily invalid in a strict data entry sense. Yes, it isn't in use in the real world, which is a problem if you're entering a shipping address, for example, but that doesn't mean it won't be real someday. ZIP codes are not etched in stone, and in fact they are created anew on a fairly regular basis in fast-growing areas. That's the beauty of relying on a third-party service to handle the ZIP code lookup—it is responsible for keeping its ZIP code database up to date, not you.

Regardless of how you handle the issue of a ZIP code not being used in the real world, hopefully you can see how the Validator application lays some important groundwork in data validation that you can reuse and repurpose in all kinds of useful ways.


ch07lev1sec5.html

Giving Validator an Extreme Ajax Makeover

The Validator application is one of the more immediately applicable examples in the book because intelligent data entry is a common need. The validatekit.js file offers functions for common data types that are often used in data entry forms. The first way to expand upon the Validator example is to apply the validation functions to your own user-input forms. This is as easy as importing the validatekit.js file into your pages via the following <script> tag:

<script type="text/javascript" src="validatekit.js"> </script>

Then code the HTML elements for validation by calling the appropriate validation function and passing along the IDs of the HTML elements. As an example, if you wanted to validate the age of a person to make sure it is an integer number, you might create the following text box and help field:

<input id="age" type="text" size="4"
  onblur="validateInteger(this,
  document.getElementById('age_help'))" />
<span id="age_help" class="help"></span>

You don't have to associate a style class with the help text, but it does make the user interface look a little better. Here's an example of a help style that you can use to dress up the help fields:

<style type="text/css">
  span.help { color:#AA0000; font-style:italic; }
</style>

Keep in mind that this style must be placed in the head of the Web page, which is also where the <script> tag you saw a moment ago must be placed. This style just makes the help text italicized and red. You can easily add on more styles or tweak these to get a different look.

The one problem with this age validator is that it doesn't account for the user entering an age that doesn't make sense. For example, because the validation only checks to see if the input is an integer, no help text is displayed if the user enters an age of -5 or 212. And until someone uncovers the fountain of youth, an age much over 100 can probably be considered invalid. You could account for negative ages by possibly creating a whole new validation function that only allows positive integers, but in this particular case a range validation makes more sense.

The age range validation is responsible for first checking that an input value is an integer, and then further checking to see if the integer is within an acceptable range, such as 1 to 120. Following is how you might put together a validation function to carry out this task:

function validateAge(inputControl, helpControl) {
  // First see if the input value is an integer
  if (!validateInteger(inputControl, helpControl))
    return false;
  // Then see if the input value is in the prescribed range
  if (inputControl.value < 1 || inputControl.value > 120) {
    if (helpControl != null)
      helpControl.innerHTML = "Please enter an age in the
      range 1 - 120.";
    return false;
  }
  else {
    if (helpControl != null)
      helpControl.innerHTML = "";
    return true;
  }
}

Notice that this function first calls the validateInteger() function to check and make sure the input is indeed a valid integer. There's no sense in moving on to the range check if the input isn't an integer. If the input is an integer, a range check is performed. The result of the range check is to simply set or clear text in the help control. The help control is checked for a null value in the event that you forget or decide not to include a help control, in which case you don't want an error to occur.

Even if your JavaScript experience is shaky or nonexistent, you should be able to isolate the key part of the validateAge() function and modify it to fit your needs. For example, you can change the range of the validation check by simply changing this line of code:

if (inputControl.value < 1 || inputControl.value > 120) {

Let's say you want to validate an NFL (National Football League) quarterback rating, which must be in the range 0 to 158. Here's how you would change the range-testing line of code:

if (inputControl.value < 0 || inputControl.value > 158) {

Note

Please don't ask why an NFL quarterback rating is in the range 0 to 158 (actually 158.33), as opposed to something more logical such as 0 to 10. It's a tricky calculation that factors in variables such as pass completion percentage, yards per attempt, touchdowns per attempt, etc. Unless you're a total (American) football nerd, just accept the range and move on. Otherwise, feel free to learn more at http://en.wikipedia.org/wiki/Passer_rating.

Hopefully you can see that crafting your own validation functions out of the base set I've provided isn't terribly difficult.

It's also possible to extend the Ajax-style validation employed by the Validator application in looking up the city and state of a ZIP code. For example, a popular Ajax validation is to check a database of user names to ensure uniqueness when registering a new user. In this case, you would issue an Ajax request to your server script that passes along the user name entered, and the server script then checks the name against a database of existing user names to see if it is unique. The response could be as simple as "yes" or "no" for the uniqueness validation. So the client just needs to look at this result and display a help message accordingly.

The point to this makeover discussion is that I've really only exposed the tip of the iceberg in terms of data validation and Ajax. It's up to you to take what you've learned and the code I've provided to further expand on the validation techniques as needed.


ch07lev1sec6.html

Summary

Although this book presents lots of interesting Ajax applications, some with impressive visuals and live data feeds, from a purely practical perspective few of them are as immediately handy as the Validator application. The application has a very basic user interface, but it's the usability that shines here. The help text that appears when invalid data is entered is subtle but compelling. And consider that this help information appears immediately without you having to submit any data—this is the "Ajax" way of doing things, even when an Ajax server request isn't explicitly being made. Of course, the Validator application does involve an Ajax server request for obtaining the city and state for a ZIP code, but the fact remains that the application promotes an "Ajax" feel throughout, even when the validation is taking place solely on the client.


ch08.html

Chapter 8. A Killer Interface for Image Viewing

Ajax and Early Plumbing

It's hard to believe, but Ajax has some humble beginnings in sixteenth-century plumbing. In 1596 Sir John Harrington invented a flush toilet called "The Ajax" for Queen Elizabeth I of England. The Ajax toilet design didn't exactly catch on in England, but it did see some success in France. The modern S-trap toilet design didn't appear until nearly 200 years later.

We all know a picture is worth a thousand words, especially in the highly visual realm of the modern Web. However, the current technique for viewing images on the Web is a bit primitive and boring. I'm assuming that you're using a small image thumbnail as a link to a full-size version of an image, which makes sense for most photographs given that you don't want to hog screen space on a page with a huge photograph. The traditional way of handling thumbnail images is to simply link to the full-size image, in which case the browser opens and displays the image as if it is another Web page. This counts as a page navigation, meaning you have to click the Back button on your browser to return to the original page, including a possible reload. This is a less-than-ideal way to view images and involves far too much loading and reloading. "Ajax" offers a much better alternative.

This chapter presents you with a slick "Ajax" image viewer that eliminates the need to open the full size version of a thumbnail image in another page, thereby ditching the whole Back button reload problem. I keep quoting the word "Ajax" because you don't technically need Ajax to carry out this image-viewing functionality. You'll find out why as you dig into the challenge for this chapter, but understand that this chapter presents a perfect example of an Ajax-style effect that doesn't technically involve an Ajax request.

The following files are used by the Imaginator application in this chapter, and are located on the live Linux CD-ROM with the book in the chap08 example code folder:

  • imaginator.html—Main Web page

  • smokiesXX.jpg—Series of Smoky Mountain example images

  • smokiesXX_thumb.jpg—Thumbnailed series of Smoky Mountain example images

  • domkit.js—DOM-related functions for the Ajax Toolkit

  • modalimgkit.js—Modal image-related functions for the Ajax Toolkit

  • modalimgkit.css—Style sheet for modal images

  • modalimgkit_wait.gif—Animated "loading" icon that is displayed while loading a modal image

  • modalimgkit_gray.png—Transparent gray image that is displayed against the background page while viewing a modal image in the foreground

The Challenge: Loading Images Dynamically

An inherent problem exists with how thumbnail images are typically handled on Web pages. The root of the problem is that you must initiate a full-blown HTTP request via a link in order to view the full-size image. This means the image is loaded as if it is another Web page, meaning that the browser navigates away from the page with the thumbnail to a new "page" containing the image. If you're on a slow Internet connection or are viewing a particularly large image, the time spent waiting on the image to load can be confusing because there is no visual cue that the image is being loaded, unless you consider a frozen browser a cue.

A secondary problem is that you have to click the Back button in order to return to the original page with the thumbnail. This is important because the idea of the Forward and Back buttons on a browser is to lead you between pages that are unique from one another. In other words, leaving a page via a link should take you somewhere completely different, not just provide you with a different view of something that is already on the page. A view of a full-size image doesn't constitute "new" content, which is why I really dislike the idea of having to browse forward to view an image, and then browse back to return to the original page.

So can Ajax help solve this problem? Not really. The problem with Ajax in this scenario is that it is designed around the notion of querying a server for text data. As you are probably well aware, images are binary, not text. If you're curious as to that distinction, try dragging and dropping an image onto your favorite text editor. You'll see a bunch of garbled characters that don't make any sense, because image formats aren't geared toward text representation. Because of this, you'd have serious problems in trying to request an image via Ajax.

We've established that Ajax can't be used to dynamically load an image via a request, which is a bummer because this would definitely solve the whole "load a new page to view an image" dilemma. But this doesn't mean we're out of options. In fact, a mechanism in the standard JavaScript Image object makes it possible to achieve the general effect of Ajax without ever issuing an Ajax request. I'm referring to the onload event in the Image object, which notifies you when an image has finished loading. This event in many ways works like an Ajax request because it issues a notification when an image finishes loading.

Another component of the Image object that assists the onload event handler is the complete member variable, which is a Boolean (true/false) piece of data that lets you know whether an image has finished loading. When combined with the onload event handler, the complete member variable gives you everything you need to construct an "Ajax" image viewer.

Although I'm sure you would enjoy a fascinating in-depth discussion of the onload event handler and complete member variable, especially if you aren't a JavaScript whiz, I'll spare you the suffering. Instead, I'm happy to share that I've already built some JavaScript code that allows you to inject a slick image viewer into your pages with almost no work at all. Seriously, you're going to be surprised at the utter simplicity of this chapter's example.

The code that supports the image viewer is part of the modalimgkit.js file included as part of the Ajax Toolkit on the CD-ROM with this book, and it's also a part of the source code files for the Imaginator sample application. As was originally mentioned back in Chapter 2, "Inside an Ajax Application," the modalimg.js file offers a single JavaScript function you can use to automatically convert image links on an entire page to Ajax-style image viewer links. This function is called initModal(), and it must be called in the onload event handler of the body of a page containing image links.

The beauty of the initModal() function is that it automatically scans through the page finding image links and then alters them so that they use a dynamic Ajax-style image viewer. Because the function automatically doctors every image link it finds on a page, you don't have to do anything more than call it once in order to activate the dynamic image viewer.

Note

The word modal in the modalimgkit.js file refers to the fact that the dynamic image viewer uses a modal window, which is a window that prevents you from interacting with parent windows while it is visible. Modal windows are used a great deal throughout most modern operating systems via dialog boxes. For example, the About box in most Windows applications is a modal window. The dynamic image viewer uses modal windows so that you can't accidentally click the window in the background while viewing an image.

Note

In case you're wondering, other Ajax-style image viewer toolkits are available that you can download and use for free. Some of them are even more powerful than the one you learn about here. However, you'll be hard pressed to find one as compact and easy to use as this one. My goal was to simplify and minimize the code as much as possible while still providing a slick visual feature. Sometimes less really is more!


ch08lev1sec1.html

Chapter 8. A Killer Interface for Image Viewing

Ajax and Early Plumbing

It's hard to believe, but Ajax has some humble beginnings in sixteenth-century plumbing. In 1596 Sir John Harrington invented a flush toilet called "The Ajax" for Queen Elizabeth I of England. The Ajax toilet design didn't exactly catch on in England, but it did see some success in France. The modern S-trap toilet design didn't appear until nearly 200 years later.

We all know a picture is worth a thousand words, especially in the highly visual realm of the modern Web. However, the current technique for viewing images on the Web is a bit primitive and boring. I'm assuming that you're using a small image thumbnail as a link to a full-size version of an image, which makes sense for most photographs given that you don't want to hog screen space on a page with a huge photograph. The traditional way of handling thumbnail images is to simply link to the full-size image, in which case the browser opens and displays the image as if it is another Web page. This counts as a page navigation, meaning you have to click the Back button on your browser to return to the original page, including a possible reload. This is a less-than-ideal way to view images and involves far too much loading and reloading. "Ajax" offers a much better alternative.

This chapter presents you with a slick "Ajax" image viewer that eliminates the need to open the full size version of a thumbnail image in another page, thereby ditching the whole Back button reload problem. I keep quoting the word "Ajax" because you don't technically need Ajax to carry out this image-viewing functionality. You'll find out why as you dig into the challenge for this chapter, but understand that this chapter presents a perfect example of an Ajax-style effect that doesn't technically involve an Ajax request.

The following files are used by the Imaginator application in this chapter, and are located on the live Linux CD-ROM with the book in the chap08 example code folder:

  • imaginator.html—Main Web page

  • smokiesXX.jpg—Series of Smoky Mountain example images

  • smokiesXX_thumb.jpg—Thumbnailed series of Smoky Mountain example images

  • domkit.js—DOM-related functions for the Ajax Toolkit

  • modalimgkit.js—Modal image-related functions for the Ajax Toolkit

  • modalimgkit.css—Style sheet for modal images

  • modalimgkit_wait.gif—Animated "loading" icon that is displayed while loading a modal image

  • modalimgkit_gray.png—Transparent gray image that is displayed against the background page while viewing a modal image in the foreground

The Challenge: Loading Images Dynamically

An inherent problem exists with how thumbnail images are typically handled on Web pages. The root of the problem is that you must initiate a full-blown HTTP request via a link in order to view the full-size image. This means the image is loaded as if it is another Web page, meaning that the browser navigates away from the page with the thumbnail to a new "page" containing the image. If you're on a slow Internet connection or are viewing a particularly large image, the time spent waiting on the image to load can be confusing because there is no visual cue that the image is being loaded, unless you consider a frozen browser a cue.

A secondary problem is that you have to click the Back button in order to return to the original page with the thumbnail. This is important because the idea of the Forward and Back buttons on a browser is to lead you between pages that are unique from one another. In other words, leaving a page via a link should take you somewhere completely different, not just provide you with a different view of something that is already on the page. A view of a full-size image doesn't constitute "new" content, which is why I really dislike the idea of having to browse forward to view an image, and then browse back to return to the original page.

So can Ajax help solve this problem? Not really. The problem with Ajax in this scenario is that it is designed around the notion of querying a server for text data. As you are probably well aware, images are binary, not text. If you're curious as to that distinction, try dragging and dropping an image onto your favorite text editor. You'll see a bunch of garbled characters that don't make any sense, because image formats aren't geared toward text representation. Because of this, you'd have serious problems in trying to request an image via Ajax.

We've established that Ajax can't be used to dynamically load an image via a request, which is a bummer because this would definitely solve the whole "load a new page to view an image" dilemma. But this doesn't mean we're out of options. In fact, a mechanism in the standard JavaScript Image object makes it possible to achieve the general effect of Ajax without ever issuing an Ajax request. I'm referring to the onload event in the Image object, which notifies you when an image has finished loading. This event in many ways works like an Ajax request because it issues a notification when an image finishes loading.

Another component of the Image object that assists the onload event handler is the complete member variable, which is a Boolean (true/false) piece of data that lets you know whether an image has finished loading. When combined with the onload event handler, the complete member variable gives you everything you need to construct an "Ajax" image viewer.

Although I'm sure you would enjoy a fascinating in-depth discussion of the onload event handler and complete member variable, especially if you aren't a JavaScript whiz, I'll spare you the suffering. Instead, I'm happy to share that I've already built some JavaScript code that allows you to inject a slick image viewer into your pages with almost no work at all. Seriously, you're going to be surprised at the utter simplicity of this chapter's example.

The code that supports the image viewer is part of the modalimgkit.js file included as part of the Ajax Toolkit on the CD-ROM with this book, and it's also a part of the source code files for the Imaginator sample application. As was originally mentioned back in Chapter 2, "Inside an Ajax Application," the modalimg.js file offers a single JavaScript function you can use to automatically convert image links on an entire page to Ajax-style image viewer links. This function is called initModal(), and it must be called in the onload event handler of the body of a page containing image links.

The beauty of the initModal() function is that it automatically scans through the page finding image links and then alters them so that they use a dynamic Ajax-style image viewer. Because the function automatically doctors every image link it finds on a page, you don't have to do anything more than call it once in order to activate the dynamic image viewer.

Note

The word modal in the modalimgkit.js file refers to the fact that the dynamic image viewer uses a modal window, which is a window that prevents you from interacting with parent windows while it is visible. Modal windows are used a great deal throughout most modern operating systems via dialog boxes. For example, the About box in most Windows applications is a modal window. The dynamic image viewer uses modal windows so that you can't accidentally click the window in the background while viewing an image.

Note

In case you're wondering, other Ajax-style image viewer toolkits are available that you can download and use for free. Some of them are even more powerful than the one you learn about here. However, you'll be hard pressed to find one as compact and easy to use as this one. My goal was to simplify and minimize the code as much as possible while still providing a slick visual feature. Sometimes less really is more!


ch08lev1sec2.html

The Design: Designing a Dynamic Image Viewer

The sample application in this chapter is called Imaginator, and its job is primarily to demonstrate how ridiculously easy it is to use the modal image viewer portion of the Ajax Toolkit included with the book. All the Imaginator application really has to do is present several linked thumbnail images, and then properly call the initModal() function to turn on the image viewer. From there, everything is automatic.

You also have to include the modalimgkit.js JavaScript file in the Imaginator page, as well as its associated style sheet, modalimgkit.css. This style sheet defines the styles used by the modal image window to get a clean look when displaying an image on the screen.

The Imaginator application presents a series of thumbnail images used as the basis for dynamic image viewing, which means that clicking any one of these images results in the loading of the full-size image associated with the thumbnail and the tracking of the loading status. The Imaginator page stays in view at all times, although it is hidden behind a transparent gray overlay while an image is being displayed by the image viewer. Figure 8.1 shows how only one image in the series of thumbnail images is capable of being viewed at full size at any given time.

Figure 8.1. The Imaginator application consists of a series of linked thumbnail images that can be viewed individually at full size.

What this figure doesn't show is how the entire Imaginator Web page is automatically disabled by the image viewer while a full-size image is being displayed. Not only that, but an animated "loading" image is displayed while the image is loading to help clue the user in on the fact that he or she is waiting for the image to load. This image is part of the image viewer, but there's nothing stopping you from changing it to something else. Figure 8.2 shows the modalimgkit_wait.gif image used by the image viewer.

Figure 8.2. The dynamic image viewer used by the Imaginator makes use of an animated "loading" image (modalimgkit_wait.gif) to let the user know an image is being loaded.

The animated "loading" image is displayed in place of the image while the image is being loaded. Once the image finishes loading, it replaces the "loading" image. You can think of the "loading" image as a placeholder that appears in lieu of an image while it is being loaded.


ch08lev1sec3.html

Putting Together the Imaginator Application

Assembling the Imaginator application is quite trivial thanks to the image viewer in the Ajax Toolkit—the application consists of only an HTML Web page and several images. More specifically, the Web page imaginator.html includes a series of thumbnail images that link to a full-size version of each thumbnail. Figure 8.3 shows the Imaginator application with a full-size modal image in view and the series of thumbnail images visible in the background.

Figure 8.3. The Imaginator Web page consists of a series of thumbnail images that link to their full-size counterparts.

[View full size image]

The body of the Imaginator Web page is responsible for arranging the thumbnail images on the page and establishing links to the full-size images. Following is the code for the body of the page:

Code View:
<body onload="initModal()">
  <p>Following are some pictures from a recent trip to the Great
    Smoky Mountains.</p>
  <table>
    <tr>
      <td><a href="smokies01.jpg"><img src="smokies01_thumb.jpg"
        alt="The Great Smoky Mountains" style="border:none"/>
        </a></td>
      <td><a href="smokies02.jpg"><img src="smokies02_thumb.jpg"
        alt="The Great Smoky Mountains" style="border:none"/>
        </a></td>
      <td><a href="smokies03.jpg"><img src="smokies03_thumb.jpg"
        alt="The Great Smoky Mountains" style="border:none"/>
        </a></td>
      <td><a href="smokies04.jpg"><img src="smokies04_thumb.jpg"
        alt="The Great Smoky Mountains" style="border:none"/>
        </a></td>
      <td><a href="smokies05.jpg"><img src="smokies05_thumb.jpg"
        alt="The Great Smoky Mountains" style="border:none"/>
        </a></td>
    </tr>
  </table>
</body>

The most important piece of code in the entire application is the first line of code in the body, which calls the initModal() function in the Ajax Toolkit to initialize the dynamic image viewer. This function is located in the file modalimgkit.js, and its job is to take care of processing all the image links on the page so that they use the Ajax-style image viewer instead of a traditional link approach. The initModal() function also preloads the images used by modal images, including the animated "loading" icon (modalimgkit_wait.gif) and the transparent gray background image (modalimgkit_gray.png).

The remaining code in the body of the page is straight HTML code that wraps <a> tags around <img> tags to create linked thumbnail images. Notice that the thumbnail images are all named with _thumb as the filename suffix. You don't have to use this identical naming convention, but it's a very good idea to establish some consistency when naming related files, such as thumbnail and full-size image pairs.

Earlier I mentioned that you need to import the image viewer files from the Ajax Toolkit into the Imaginator Web page. These files include a CSS style sheet and a JavaScript file. Following is how you import the style sheet, which is named modalimgkit.css:

<link rel="stylesheet" type="text/css" href="modalimgkit.css" />

Similarly, the modalimgkit.js JavaScript file is imported with the following line of code:

<script type="text/javascript" src="modalimgkit.js"> </script>

Both of these lines of code must be placed in the head of the page. Just to make sure you understand how the files are imported, here is the full head of the Imaginator Web page:

<head>
  <title>Imaginator</title>

  <link rel="stylesheet" type="text/css"
    href="modalimgkit.css" />
  <script type="text/javascript" src="domkit.js"> </script>
  <script type="text/javascript" src="modalimgkit.js"> </script>
</head>

This code reveals how the Imaginator Web page also includes the domkit.js file from the Ajax Toolkit, which offers several helper functions for carrying out standard JavaScript DOM tasks such as determining the client window size, getting and replacing element text, etc.

The only other missing ingredients in the Imaginator application are the two images required by the image viewer. You've already seen one of them, modalimgkit_wait, which serves as an animated "loading" image that is shown while an image is being loaded. The other, modalimgkit_gray.png, is a tiny gray image with transparency that is used to gray out the background window while an image is being viewed. This image is able to gray out the entire background by being repeated across the image viewer window behind the image itself. This visual trick is accomplished by the image viewer's CSS style sheet. All you need to worry about is making sure the two images are in the same folder as the Imaginator Web page.

When you click a link to a modal image, the tiny gray transparent image is tiled across the background to give the underlying page a "disabled" appearance, while the animated "loading" image is displayed in the center of the page during the loading of the modal image. Once the modal image finishes loading, it replaces the animated image. When you click to close the modal image, both it and the gray transparent background image go away.


ch08lev1sec4.html

Testing Imaginator

Testing the Imaginator application is pretty much as simple as putting it together, and involves clicking thumbnail images and making sure they appear properly in full size. Figure 8.4 shows the Imaginator application open initially with the thumbnail images in view and no full-size image displayed.

Figure 8.4. When the Imaginator application first begins, you see only a series of thumbnail images.

[View full size image]

To see the dynamic image viewer in action, click one of the thumbnail images. Figure 8.5 shows the "loading" image that appears while the image is being loaded.

Figure 8.5. A "loading" image appears in front of a grayed background while a full-size image is being loaded.

[View full size image]

It's very important to note how the background behind the "loading" image has been grayed to prevent access to the underlying page while the image is being loaded. This visually hammers home the fact that the image viewer is modal, and helps to put total focus on the full-size image, or in this case the fact that it is being loaded.

After a few short moments, the full-size image will appear in place of the "loading" image, as shown in Figure 8.6.

Figure 8.6. Once loaded, the full-size image appears in place of the "loading" image.

[View full size image]

Again, the background window remains grayed while the full-size image is being viewed. To close the image, just click it with the mouse or press Enter or the spacebar on the keyboard. You are immediately returned to the original page where you can view another image or otherwise resume Web surfing.

The key to the Imaginator application is that you never needed to navigate away from the original page in order to view a full-size image. Not only that, but you are presented with a very clear visual cue that an image is being loaded, as opposed to you just waiting for the browser to churn away while it opens the full-size image in a new "page."


ch08lev1sec5.html

Giving Imaginator an Extreme Ajax Makeover

You may be wondering how there could be much room to make over the Imaginator application given that the image viewer is quite focused in solving a very specific problem. Although you could certainly consider enhancing the image viewer itself by possibly supporting captions or annotated audio clips, that would only serve to complicate things, or at the very least require considerable development effort.

A more apt extreme makeover for the Imaginator application is to experiment with your own images. In fact, the best way to experiment is to take an existing page with thumbnail images on it and just try out the image viewer with no other changes. All you have to do is add the two import lines of code to the head of the page and then add the initModal() function call to the body's onload event handler. Then make sure you copy the source files (modalimgkit.css and modalimgkit.js) and images (modalimgkit_wait.gif and modalimgkit_gray.png) over to the folder containing your page, and you're good to go. This is a great test because it shows how truly plug-and-play the dynamic image viewer can be.

Another fun way to make over the Imaginator application is to try out a different animated "loading" image. If you're a crafty graphic designer, you may be able to whip one up on your own. For the rest of us, there is a very cool online tool that allows you to generate your own custom Ajax "loading" images. The Web site is called AjaxLoad.info (http://www.ajaxload.info/), and you can see it in action in Figure 8.7.

Figure 8.7. The AjaxLoad.info Web site allows you to generate custom animated "loading" images for Ajax applications.

[View full size image]

Using this tool, you pick the type of indicator (icon) along with its background and foreground colors, and the tool generates an animated image for you. You can even look at a preview in order to fine-tune an image before you elect to download the finished result.

Once you arrive at an animated "loading" image that you like, just copy it over the existing modalimgkit_wait.gif image in the Imaginator folder (or the folder of your own Web page). Replacing the GIF file will immediately replace the image in the image viewer, although it may require a browser refresh if you've already opened the Imaginator page prior to copying the image.


ch08lev1sec6.html

Summary

One of the goals of this book is to build practical Ajax sample applications whose building blocks are as plug-and-play as possible. Although some components of the book's Ajax Toolkit are certainly more plug-and-play than others, few are as easy and offer as much impact as the dynamic image viewer, which provides a slick "Web 2.0"–style image viewer in exchange for only a few lines of code in your Web page. I encourage you to take advantage of the image viewer's ease of use by plugging it into your own pages and not looking back—it's rare that you get such painless bang for your buck in the world of Web development.


ch09.html

Chapter 9. Presenting Information with Slick Popups

Ajax the Town

If you ever want to visit Ajax, you can do so by venturing into south central Ontario, Canada, where you'll find the town of Ajax. Situated on the shores of Lake Ontario, Ajax is considered a suburb of Toronto. The town name came about as a result of the munitions plant that was there throughout World War II. Due to its role as a WWII munitions provider, the town was named after the warship that won the first major WWII British naval battle, HMS Ajax.

One of the most visible uses of Ajax across the Web is popup windows that automatically appear when you click or hover over a link. Even with the negative stigma associated with popup windows, the Ajax popup window technique can be quite handy when used intelligently. For example, such a popup can be displayed in response to hovering over a link, and it can provide a preview of a page before the user actually traverses the link via a click. Or even better, you can expand the notion of a "link" so that it shares information directly in a popup window instead of linking to an entirely new page. This can simplify the navigation of a site. The user is not taken to a new page unless a legitimate page worth of information is available—bite-size information can be displayed in popups.

This chapter explores the notion of an Ajax-powered information window, or info window, which is just a popup window that is dynamically fed with data obtained through an Ajax request. Info windows can be used to display just about anything, but the general idea is to display a nugget of information that doesn't necessarily warrant its own complete page. By using an info window, you make the information more immediately accessible and eliminate the need for a new page load and browser navigation.

The following files are used by the Informer application in this chapter, and are located on the live Linux CD-ROM with the book in the chap09 example code folder:

  • snapper.html—Snapper main Web page

  • informer.html—Informer main Web page

  • skateXXX.html—Series of example Web pages related to skateboards

  • skateXXX.jpg—Series of skateboard example images

  • ajaxkit.js—Core Ajax functions for the Ajax Toolkit

  • domkit.js—DOM-related functions for the Ajax Toolkit

  • infowinkit.js—Information window-related functions for the Ajax Toolkit

  • infowinkit.css—Style sheet for information windows

  • infowinkit_wait.gif—Animated "loading" icon that is displayed while loading information into an info window

The Challenge: Creating Linked Popups

Although I would certainly agree with the notion that popup windows have become one of the most negative "innovations" in the short history of the Web, sometimes a slight repurposing of a negative can lead to a positive. There's a fine line between "helpful" and "annoying." Unfortunately, popup windows have largely erred on the side of the latter. Ajax presents an opportunity to use popups in a more helpful and less obtrusive manner.

Remember that the killer feature of Ajax is its ability to query the server for bits and pieces of data, as opposed to complete Web pages. This book has already presented you with numerous examples of how it is much more efficient to dynamically load a chapter of an e-book, a stock quote, or a piece of validated user input without having to make a complete roundtrip full-page request on the server. The idea thus far, however, has been to load a chunk of information from the server and somehow display it on the current page. But what if it doesn't make sense to use the current page for display purposes?

In some situations it might be a distraction to display the results of an Ajax request directly on the current page. Consider the analogy of a sidebar or note box in this book. A sidebar or note box is intended to provide some kind of supplemental information. However, it gets placed on the page smack in the middle of the main chapter text, and thus competes for your attention. It would be much better if you could somehow turn a note on and off at will, instead of having to contend with it competing visually with the main discussion.

Note

This note is admittedly a bit distracting because it eats up precious space on the printed page and interrupts the flow of the main chapter text. Sure, you could ignore it, but you obviously aren't or you wouldn't be reading this sentence. It would be nice if you could tap the page with your finger and make this note box go away. Unfortunately, I haven't figured out how to inject Ajax into the printed page!

The point I'm making is that a popup window can be handy in a situation where you have some additional information to present but you don't want to cloud the current page being viewed. Additionally, it would be extremely handy if you didn't have to load this extra information on the front end, and instead only load it as needed. Ajax makes it possible to access such information on a need-to-know basis and then display it in a popup window that only temporarily takes up screen space.

There is obviously a lot of ill will over the abuse of popups thanks to aggressive online advertisers. For this reason, some users are averse to popups of any kind. Knowing this, it's important to be very judicious in your usage of popups, and even when justified don't force them on users. What users really hate is not having any control over the display of a popup, as is often the case with annoying popup ad windows. A more positive usage of popups is to only display them in response to a click or possibly a hover. In the latter case, it is important to automatically hide the popup once the hover finishes (i.e., when the mouse pointer leaves the element it was hovering over).

A popular Ajax popup technique that has been used with success involves the hover approach I just mentioned. I'm referring to a link preview popup where the contents of the page associated with a link are displayed in a small popup when you hover over the link.

A good example of this technique is the Snap Preview site (http://www.snap.com/), which displays a popup window that presents a preview of a linked page. Although you could write your own custom hover preview window in Ajax, there is no need because Snap Preview is in fact an online service that automates the process. Snap Preview allows you to turn all of the links on your Web pages to Snap Preview links.

Note

Another service similar to Snap Preview is Kontera (http://www.kontera.com/), which uses hover popup windows to display advertising associated with a link. Although Kontera links are still ad-based popups, they are much less intrusive than popup windows that appear without any warning.

To Snap-enable your own pages, you must first register your site with Snap at http://www.snap.com.

In addition to registering you with Snap, the Snap registration process also provides you with the JavaScript code necessary to add the Snap Preview feature to your pages. This Snap Preview JavaScript code snippet is contained within a standard <script> tag. Following is an example of such a snippet, which must be placed in the head of a Web page in order for it to use the Snap Preview feature:

<script defer="defer" id="snap_preview_anywhere"
  type="text/javascript"
  src="http://spa.snap.com/snap_preview_anywhere.js?
  ap=1&amp;key=c6a9f...&amp;
  sb=0&amp;domain=www.stalefishlabs.com"></script>

This code is actually included as part of a sample Web page I put together (snapper.html) to demonstrate how easy it is to use Snap Preview. Here's the code for the body of the page:

<body>
  <p>Here are some links:</p>
  <p><a href="http://www.usatoday.com/">USA Today</a></p>
  <p><a href="http://www.amazon.com/">Amazon.com</a></p>
  <p><a href="http://www.nhl.com/">National Hockey League</a></p>
  <p><a href="http://www.snopes.com/">Snopes.com</a></p>
  <p><a href="http://www.michaelmorrison.com/">Michael's Web
site</a></p>
</body>

As you can see, nothing specific about this code ties it to the Snap Preview functionality—the Snap Preview script automatically alters every link on a page so that it uses the feature. Figure 9.1 shows what the resulting page looks like with a preview popup window in view.

Figure 9.1. The Snap Preview popup window appears any time you hover over a link on the page, providing a small-scale preview of the page.

[View full size image]

It's very important to note that Snap Preview popups appear and disappear in response to mouse hovers and exits, not mouse clicks. When you hover over a link, a popup automatically appears, and when you hover off of (exit) the link, the popup disappears. Some people feel that even this approach to popups is a bit intrusive because it is easy to inadvertently trigger a preview when moving the mouse around on the page. An even less aggressive approach is to tie information popups to mouse clicks.

And finally we arrive at the challenge for this chapter—information popup windows that are initiated by mouse clicks. I think the Snap Preview approach to popups, which is also employed in a slightly different manner in sites such as NetFlix, is very cool, but I agree with the complaint that it can be annoying when you accidentally trigger a popup by hovering (dragging) over a link. In my opinion, the safer route is to rely on mouse clicks for popup windows. Of course, the click approach doesn't work in some cases, such as Snap Preview, because there truly is a link that must be followed when a click occurs.

The focus of this chapter is on information popup windows that don't apply to traditional links to other pages. The idea here is to essentially create a special "popup link" or "info link" that is only used when you want to display a nugget of information. This makes it possible to trigger the popup on a mouse click as opposed to a hover, and thus minimize any potential negative impact on the usability of a page. The good news is that I've already written the bulk of the code that makes information popup windows possible.

The code that supports information popups is part of the infowinkit.js file included as part of the Ajax Toolkit on the CD-ROM with this book, and it's also a part of the source code files for the Informer sample application. As was originally mentioned back in Chapter 2, "Inside an Ajax Application," the infowinkit.js file offers two JavaScript functions that are used to support dynamic information popup windows:

  • initInfoWindow()—Initialize the information popup window for the entire page

  • showInfoWindow()—Show a specific piece of dynamically loaded information in the popup window

The initInfoWindow() function is used to initialize the information popup window, and must be called in the onload event handler of the body of a page containing info links. The showInfoWindow() function is then called for each info link in the link's onclick event handler; this is what actually causes the popup window to get displayed. You learn more about the specifics of these two functions as you get into the nuts and bolts of the Informer application later in the chapter.

Getting back to the challenge associated with the Informer application, you know that information popups are used to share information. In this particular example you create a Web page about the sport of skateboarding, using information popups to describe the primary equipment involved. The idea is that the main content on the page simply mentions each piece of equipment, whereas the specifics of each piece are delegated to info links (popups). So, you'll be wrapping info links around several pieces of text on the page so that the text is linked to information popups.


ch09lev1sec1.html

Chapter 9. Presenting Information with Slick Popups

Ajax the Town

If you ever want to visit Ajax, you can do so by venturing into south central Ontario, Canada, where you'll find the town of Ajax. Situated on the shores of Lake Ontario, Ajax is considered a suburb of Toronto. The town name came about as a result of the munitions plant that was there throughout World War II. Due to its role as a WWII munitions provider, the town was named after the warship that won the first major WWII British naval battle, HMS Ajax.

One of the most visible uses of Ajax across the Web is popup windows that automatically appear when you click or hover over a link. Even with the negative stigma associated with popup windows, the Ajax popup window technique can be quite handy when used intelligently. For example, such a popup can be displayed in response to hovering over a link, and it can provide a preview of a page before the user actually traverses the link via a click. Or even better, you can expand the notion of a "link" so that it shares information directly in a popup window instead of linking to an entirely new page. This can simplify the navigation of a site. The user is not taken to a new page unless a legitimate page worth of information is available—bite-size information can be displayed in popups.

This chapter explores the notion of an Ajax-powered information window, or info window, which is just a popup window that is dynamically fed with data obtained through an Ajax request. Info windows can be used to display just about anything, but the general idea is to display a nugget of information that doesn't necessarily warrant its own complete page. By using an info window, you make the information more immediately accessible and eliminate the need for a new page load and browser navigation.

The following files are used by the Informer application in this chapter, and are located on the live Linux CD-ROM with the book in the chap09 example code folder:

  • snapper.html—Snapper main Web page

  • informer.html—Informer main Web page

  • skateXXX.html—Series of example Web pages related to skateboards

  • skateXXX.jpg—Series of skateboard example images

  • ajaxkit.js—Core Ajax functions for the Ajax Toolkit

  • domkit.js—DOM-related functions for the Ajax Toolkit

  • infowinkit.js—Information window-related functions for the Ajax Toolkit

  • infowinkit.css—Style sheet for information windows

  • infowinkit_wait.gif—Animated "loading" icon that is displayed while loading information into an info window

The Challenge: Creating Linked Popups

Although I would certainly agree with the notion that popup windows have become one of the most negative "innovations" in the short history of the Web, sometimes a slight repurposing of a negative can lead to a positive. There's a fine line between "helpful" and "annoying." Unfortunately, popup windows have largely erred on the side of the latter. Ajax presents an opportunity to use popups in a more helpful and less obtrusive manner.

Remember that the killer feature of Ajax is its ability to query the server for bits and pieces of data, as opposed to complete Web pages. This book has already presented you with numerous examples of how it is much more efficient to dynamically load a chapter of an e-book, a stock quote, or a piece of validated user input without having to make a complete roundtrip full-page request on the server. The idea thus far, however, has been to load a chunk of information from the server and somehow display it on the current page. But what if it doesn't make sense to use the current page for display purposes?

In some situations it might be a distraction to display the results of an Ajax request directly on the current page. Consider the analogy of a sidebar or note box in this book. A sidebar or note box is intended to provide some kind of supplemental information. However, it gets placed on the page smack in the middle of the main chapter text, and thus competes for your attention. It would be much better if you could somehow turn a note on and off at will, instead of having to contend with it competing visually with the main discussion.

Note

This note is admittedly a bit distracting because it eats up precious space on the printed page and interrupts the flow of the main chapter text. Sure, you could ignore it, but you obviously aren't or you wouldn't be reading this sentence. It would be nice if you could tap the page with your finger and make this note box go away. Unfortunately, I haven't figured out how to inject Ajax into the printed page!

The point I'm making is that a popup window can be handy in a situation where you have some additional information to present but you don't want to cloud the current page being viewed. Additionally, it would be extremely handy if you didn't have to load this extra information on the front end, and instead only load it as needed. Ajax makes it possible to access such information on a need-to-know basis and then display it in a popup window that only temporarily takes up screen space.

There is obviously a lot of ill will over the abuse of popups thanks to aggressive online advertisers. For this reason, some users are averse to popups of any kind. Knowing this, it's important to be very judicious in your usage of popups, and even when justified don't force them on users. What users really hate is not having any control over the display of a popup, as is often the case with annoying popup ad windows. A more positive usage of popups is to only display them in response to a click or possibly a hover. In the latter case, it is important to automatically hide the popup once the hover finishes (i.e., when the mouse pointer leaves the element it was hovering over).

A popular Ajax popup technique that has been used with success involves the hover approach I just mentioned. I'm referring to a link preview popup where the contents of the page associated with a link are displayed in a small popup when you hover over the link.

A good example of this technique is the Snap Preview site (http://www.snap.com/), which displays a popup window that presents a preview of a linked page. Although you could write your own custom hover preview window in Ajax, there is no need because Snap Preview is in fact an online service that automates the process. Snap Preview allows you to turn all of the links on your Web pages to Snap Preview links.

Note

Another service similar to Snap Preview is Kontera (http://www.kontera.com/), which uses hover popup windows to display advertising associated with a link. Although Kontera links are still ad-based popups, they are much less intrusive than popup windows that appear without any warning.

To Snap-enable your own pages, you must first register your site with Snap at http://www.snap.com.

In addition to registering you with Snap, the Snap registration process also provides you with the JavaScript code necessary to add the Snap Preview feature to your pages. This Snap Preview JavaScript code snippet is contained within a standard <script> tag. Following is an example of such a snippet, which must be placed in the head of a Web page in order for it to use the Snap Preview feature:

<script defer="defer" id="snap_preview_anywhere"
  type="text/javascript"
  src="http://spa.snap.com/snap_preview_anywhere.js?
  ap=1&amp;key=c6a9f...&amp;
  sb=0&amp;domain=www.stalefishlabs.com"></script>

This code is actually included as part of a sample Web page I put together (snapper.html) to demonstrate how easy it is to use Snap Preview. Here's the code for the body of the page:

<body>
  <p>Here are some links:</p>
  <p><a href="http://www.usatoday.com/">USA Today</a></p>
  <p><a href="http://www.amazon.com/">Amazon.com</a></p>
  <p><a href="http://www.nhl.com/">National Hockey League</a></p>
  <p><a href="http://www.snopes.com/">Snopes.com</a></p>
  <p><a href="http://www.michaelmorrison.com/">Michael's Web
site</a></p>
</body>

As you can see, nothing specific about this code ties it to the Snap Preview functionality—the Snap Preview script automatically alters every link on a page so that it uses the feature. Figure 9.1 shows what the resulting page looks like with a preview popup window in view.

Figure 9.1. The Snap Preview popup window appears any time you hover over a link on the page, providing a small-scale preview of the page.

[View full size image]

It's very important to note that Snap Preview popups appear and disappear in response to mouse hovers and exits, not mouse clicks. When you hover over a link, a popup automatically appears, and when you hover off of (exit) the link, the popup disappears. Some people feel that even this approach to popups is a bit intrusive because it is easy to inadvertently trigger a preview when moving the mouse around on the page. An even less aggressive approach is to tie information popups to mouse clicks.

And finally we arrive at the challenge for this chapter—information popup windows that are initiated by mouse clicks. I think the Snap Preview approach to popups, which is also employed in a slightly different manner in sites such as NetFlix, is very cool, but I agree with the complaint that it can be annoying when you accidentally trigger a popup by hovering (dragging) over a link. In my opinion, the safer route is to rely on mouse clicks for popup windows. Of course, the click approach doesn't work in some cases, such as Snap Preview, because there truly is a link that must be followed when a click occurs.

The focus of this chapter is on information popup windows that don't apply to traditional links to other pages. The idea here is to essentially create a special "popup link" or "info link" that is only used when you want to display a nugget of information. This makes it possible to trigger the popup on a mouse click as opposed to a hover, and thus minimize any potential negative impact on the usability of a page. The good news is that I've already written the bulk of the code that makes information popup windows possible.

The code that supports information popups is part of the infowinkit.js file included as part of the Ajax Toolkit on the CD-ROM with this book, and it's also a part of the source code files for the Informer sample application. As was originally mentioned back in Chapter 2, "Inside an Ajax Application," the infowinkit.js file offers two JavaScript functions that are used to support dynamic information popup windows:

  • initInfoWindow()—Initialize the information popup window for the entire page

  • showInfoWindow()—Show a specific piece of dynamically loaded information in the popup window

The initInfoWindow() function is used to initialize the information popup window, and must be called in the onload event handler of the body of a page containing info links. The showInfoWindow() function is then called for each info link in the link's onclick event handler; this is what actually causes the popup window to get displayed. You learn more about the specifics of these two functions as you get into the nuts and bolts of the Informer application later in the chapter.

Getting back to the challenge associated with the Informer application, you know that information popups are used to share information. In this particular example you create a Web page about the sport of skateboarding, using information popups to describe the primary equipment involved. The idea is that the main content on the page simply mentions each piece of equipment, whereas the specifics of each piece are delegated to info links (popups). So, you'll be wrapping info links around several pieces of text on the page so that the text is linked to information popups.


ch09lev1sec2.html

The Design: Designing an Information Popup Application

The Informer application is really just a normal Web page with a few specialty links that are made interesting with the assistance of information popup windows. Because an info link is triggered via a mouse click, the associated popup window appears over the clicked link. Figure 9.2 shows the conceptual user interface for the Informer application, complete with a popup window that appears over an info link.

Figure 9.2. The user interface for the Informer application consists of a standard Web page with special info links capable of triggering a popup window.

The figure reveals how a link on the page results in the display of a popup window that is overlaid on the page where the link is located. Although the code that powers the popups is contained in the Ajax Toolkit, the information that gets displayed in the popups is HTML code that is ultimately your responsibility. This HTML code is stored in separate files that map one-to-one with information popup windows. This allows the Informer application to make an Ajax request for a specific file in response to each popup window. So you can think of the contents of each popup window as a mini Web page.

The design of the application therefore isn't just about importing the appropriate JavaScript code but also involves the creation of content for the popup windows. The good news is that this content is pure HTML code with no special scripting required.

Although the Ajax request within the Informer application takes place inside the infowinkit.js file, it's worth evaluating what is involved in making a request on behalf of an information popup. The next few sections quickly explore the Ajax request and response associated with an information popup.

The Client Request

The information displayed in popup windows within the Informer application is loaded from discrete files that act as mini Web pages. For example, clicking a link for skateboard wheels will display a popup that shows a picture of wheels and a description of them. This picture and description are stored in an HTML file such as skatewheels.html, which is dynamically loaded via an Ajax request when the popup window is displayed. The client request for an information popup window therefore consists solely of the URL for an information Web page.

Keep in mind that the Web page URL sent along in a client request doesn't actually reference a complete Web page. This is because the resulting HTML content will be injected into an existing popup window, as opposed to being opened in a browser as a true Web page. You can think of the HTML content for an information window as an HTML document "fragment."

The Server Response

The document "fragment" notion for information popup windows should clue you in to what the server returns in response to a request made by the Informer application. Indeed, the server simply returns a document fragment as stored in the HTML file referenced by the request URL. So, in the skateboard wheel example, the client request includes the URL of the file (skatewheels.html), whereas the server response is the actual HTML code for the mini page.

Because the server is responding with a complete file (even if its contents represent a fragment of HTML code), it isn't necessary to do any special processing on the server. Therefore, you don't need a PHP script of any kind for the Informer application.

Making Sense of the Client-to-Server Conversation

The Informer application uses very straightforward Ajax communication thanks to the Ajax Toolkit. Figure 9.3 reveals how the process of dynamically loading content into an information popup window involves sending a URL and getting HTML code (content) in response.

Figure 9.3. The Informer application uses a URL as the basis for a client request that results in information content being delivered by the server.

A client request in the Informer application consists solely of the URL for the HTML file representing the information content. No parameters are necessary since you're only interested in the HTML file, so the Ajax request results in the loading of an entire file, which in this case contains HTML code for an information "page."

I quote the word "page" when referring to the information content because it is more of an HTML document fragment as compared to a complete page. The following is an example of the information content that describes skateboard wheels:

<table>
 <tr>
   <td rowspan="2"><img src='skatewheels.jpg'
     alt='Skateboard wheels' /></td>
   <td style="font-weight:bold; background-color:#CCCCCC">
     Skateboard Wheels</td>
 </tr>
 <tr>
   <td>Although other materials have been used in the past,
     modern skateboard wheels are all manufactured out of
     urethane. Urethane skateboard wheels come in a variety of
     different sizes and hardnesses for varying terrain.
   </td>
 </tr>
</table>

This content is stored in the file skatewheels.html and consists of an image, a title, and descriptive text. The HTML code is returned as a server response in Informer, and is then inserted into the popup window that is displayed to provide additional information about skateboard wheels.


ch09lev1sec3.html

Putting Together the Informer Application

The Informer application makes heavy use of the information window support in the Ajax Toolkit, which is included on the accompanying CD-ROM. In addition to the Ajax Toolkit, the Informer application requires a couple of other components:

  • HTML Web page (informer.html)

  • Information content pages

The HTML Web page for Informer is the Web page containing the info links, whereas the information content pages describe specific pieces of content and serve to drive the popup windows. The next couple sections take a look at these parts of the Informer application in more detail.

The Informer Web Page

The Informer application consists of several HTML files, but only one of them serves as the main Web page for the application. The main Informer page is where the info links are contained, as shown in Figure 9.4.

Figure 9.4. The Informer Web page consists of a paragraph of text containing info links that launch an information popup window when clicked.

[View full size image]

The figure reveals how numerous info links are present in the paragraph of text found in the Informer Web page. Clicking any of these links results in the display of an information popup window, which is also shown in the figure. Although the popup window is primarily controlled via JavaScript code in the Ajax Toolkit, the body of the Informer page is laid out in its HTML code:

Code View:
<body onload="initInfoWindow(325, 200)">
  <div id="ajaxState" style="display:none"></div>
  <br />
  <h2>Informer - Skateboarding Basics</h2>
  <p>Skateboarding has increased considerably in the past few
    years as a major sport among America's youth. Although the
    equipment involved in skateboarding is fairly
    straightforward, there is still some degree of education
    involved for newcomers to the sport. Regardless of what type
    of skateboarding you plan on doing, you will no doubt need
    the core components of a skateboard, which consist of a
    <a href="#" class="info"
    onclick="return showInfoWindow('skatedeck.html', event)">
    deck</a>, <a href="#" class="info"
    onclick="return showInfoWindow('skatetrucks.html',
    event)">trucks</a>, and <a href="#" class="info"
    onclick="return showInfoWindow('skatewheels.html',
    event)">wheels</a>.
    Additionally, it's a good idea to consider a <a href="#"
    class="info" onclick="return showInfoWindow(
    'skatehelmet.html', event)">
    helmet</a> and <a href="#" class="info"
    onclick="return showInfoWindow('skatepads.html', event)">
    pads</a>, especially if you plan on skating any tall
    obstacles such as vert ramps and concrete bowls.
  </p>

</body>

The first important piece of code in this listing is the onload event handler for the body of the page, which makes a call to the initInfoWindow() function in the Ajax Toolkit. Notice that two parameters are passed into this function (325 and 200), which are the width (325) and the height (200) of the popup window, in pixels. This width and height is fixed throughout the life of the application, meaning that the popup window doesn't change size once the width and height are initially set.

The next piece of code worth a second look is the code that creates the info links via familiar anchor tags (<a>). Following is an example of one of the info links that appears in the body HTML code:

<a href="#" class="info"
  onclick="return showInfoWindow('skatedeck.html', event)">deck</a>

Notice that the href attribute, which usually points to the URL for the link, is set to "#". This basically tells the link that it isn't linking anywhere. Instead, the link serves as a trigger for an information popup window, which is displayed via a call to the showInfoWindow() function in the onclick event handler. When the user clicks the linked text, deck, the showInfoWindow() function is called and the popup window is displayed.

The first parameter to the showInfoWindow() function is the URL of the page to be displayed. If you recall from earlier, the information pages are actually page fragments because they are intended for display within an existing popup window. You find out more about the structure of these pages in the next section. The second parameter to the function is the standard JavaScript event object that is necessary in order to pass along the coordinates of the mouse click.

Note

In reality, the "standard" JavaScript event object isn't all that standard, meaning that it isn't supported across all browsers. However, the Ajax Toolkit is smart enough to account for browser inconsistencies and adjust the event-handling code appropriately.

Keep in mind that the showInfoWindow() function is ultimately responsible for issuing the Ajax request that loads the information content. To better understand how the showInfoWindow() function results in an Ajax request, check out the following code excerpt from the function as it appears within the infowinkit.js file:

function showInfoWindow(infoURL, evt) {
  ...
  ajaxSendRequest("GET", infoURL, handleContentRequest);
  ...
}

Notice that the URL of the "page" being loaded is passed straight through to the Ajax request thanks to the infoURL parameter. This is evidence that the Ajax request for an information popup window simply involves the loading of an HTML file.

One other little detail to notice in the HTML code for the body of the Informer page is the setting of the class attribute for the info links to "info". The info style sheet class is established in the infowinkit.css file, and it serves to style info links a little differently from standard links. These links provide a visual cue that they do something a bit beyond the ordinary. More specifically, info links appear with a double underline, and also take on a highlight when hovered over.

In order for the info style class to work, the infowinkit.css style sheet must be imported into the head of the Informer Web page (informer.html) using the following line of code:

<link rel="stylesheet" type="text/css" href="infowinkit.css" />

Similarly, the infowinkit.js JavaScript file is imported with the following line of code:

<script type="text/javascript" src="infowinkit.js"> </script>

Both of these lines of code must appear in the head of the page. Just to clarify how the files are imported, here is the full head of the Informer Web page:

<head>
  <title>Informer</title>

  <link rel="stylesheet" type="text/css" href="infowinkit.css" />
  <script type="text/javascript" src="ajaxkit.js"> </script>
  <script type="text/javascript" src="domkit.js"> </script>
  <script type="text/javascript" src="infowinkit.js"> </script>
</head>

This code reveals how the Informer Web page also includes the ajaxkit.js and domkit.js files from the Ajax Toolkit, which offer several helper functions related to Ajax and the JavaScript DOM.

With the guts of the Informer application in place, all you're missing is the content for the information popup windows themselves.

The Information Content Pages

If you refer back to the code in the body of the Informer Web page, you'll notice five info links for content related to pieces of skateboarding equipment. Each of these links references an HTML file that contains the content to be displayed in an information popup window. Following are the HTML files referenced by the Informer page:

  • skatedeck.html

  • skatetrucks.html

  • skatewheels.html

  • skatehelmet.html

  • skatepads.html

Each of these files represents a mini Web page that is displayed in a popup window when a link is clicked. Even though these files are document fragments as opposed to complete Web pages, you can still open and view them in a Web browser to see what they look like. Figure 9.5 shows the skatedeck.html file as viewed directly in a Web browser.

Figure 9.5. Each piece of information content in the Informer application is really just a mini Web page.

[View full size image]

The figure reveals how the information content for a skateboard deck consists of an image, a title, and a paragraph of text. I've used the term "fragment" several times when talking about the content files. I say this because there are no <html>, <head>, or <body> tags found in a normal Web page. Instead, the content "pages" include only enough HTML code to describe the content. To see what I mean, take a look at the following code for the skatedeck.html file shown in Figure 9.5:

<table>
 <tr>
   <td rowspan="2"><img src='skatedeck.jpg'
     alt='Skateboard deck' /></td>
   <td style="font-weight:bold; background-color:#CCCCCC">
     Skateboard Deck</td>
 </tr>
 <tr>
   <td>The deck is the most essential part of the skateboard,
     and is typically constructed out of seven layers of hard
     maple. These layers are glued and pressed in a form, and
     then cut and finished to the desired shape.
   </td>
 </tr>
</table>

Note

I'll readily admit that I broke the cardinal rule of not using tables for layout purposes, but in this case it was cleaner and simpler to lay out the skateboard content with a table. If you want to be a design purist and ditch the table for CSS, be my guest.

This code reveals how the skateboard deck mini page is described using a fragment of HTML code. This works because the code is ultimately inserted into an information popup window, as opposed to being opened as a full-blown Web page by itself.

One little detail I neglected to mention is that I only created three of the five HTML content files, deliberately leaving out the skatehelmet.html and skatepads.html files. The reason for leaving out these files is to test out the Informer application's ability to handle missing content, which you do next.


ch09lev1sec4.html

Testing Informer

Testing out the Informer application is a matter of opening the main page in a browser and clicking away. Figure 9.6 shows the page after first being loaded, prior to any of the info links being clicked.

Figure 9.6. The Informer application starts out with the information popup window hidden from view because the info links have yet to be clicked.

[View full size image]

To view an information popup window and see more details about a particular piece of skateboarding equipment, just click one of the info links. The first thing you see is a popup window with a small animated "loading" icon in the upper-left corner to let you know that content is being loaded. Figure 9.7 shows this icon in action.

Figure 9.7. An animated "loading" icon first appears in an information popup to let you know that content is being loaded.

[View full size image]

Unless you have a really slow Internet connection, the content should load very quickly, in which case the animated "loading" icon is replaced by the actual content. Figure 9.8 shows the Informer application with a popup window in view that is displaying information about skateboard decks.

Figure 9.8. An information popup appears with additional information when you click an info link in the Informer application.

[View full size image]

Of course, two of the info links on the page have been deliberately set up to fail, which provides a good test of the Ajax Toolkit's error-handling capabilities. Figure 9.9 shows what happens when you click the helmet or pads info link.

Figure 9.9. Clicking an info link with no available information content results in a popup window containing an error message.

[View full size image]

As the figure reveals, the information popup window handles the missing content about as gracefully as it possibly can, simply displaying a message that the content could not be found.


ch09lev1sec5.html

Giving Informer an Extreme Ajax Makeover

When pondering a makeover for the Informer application, one idea that quickly came to mind was first finishing the application so that it isn't missing any content. This involves creating the two missing content files for a skateboard helmet (skatehelmet.html) and skateboard pads (skatepads.html). The point is not for you to become a skateboard expert, but for you to experiment with adding content to an information window.

The best way to create these two files is to first copy one of the existing content files and use it as a template. For example, copy skatedeck.html and use it as the basis for the two missing files. You shouldn't have too much trouble finding a picture of a skateboard helmet and pads online with a little searching. Just pair up a picture with a title and some descriptive text and you'll have a content file for each of the missing topics in no time.

A more interesting way to expand on the Informer application is to completely alter the theme of the page. For example, change the focus of the content to something you're interested in, as opposed to skateboarding. Maybe you're into fishing, in which case you might write a paragraph or two about the sport, including your favorite fishing equipment. Then create info links around some of the more interesting parts of the text that could use additional descriptions.

After creating the info links in the main text, you're ready to create the content files that actually get displayed in the popups. Feel free to throw out my skateboarding templates and create something more exciting of your own. One way to change the feel of the popups is to modify their size. Remember that the width and height of the popup window is initially set when you call the initInfoWindow() function in the onload event handler of the Informer Web page. Try changing the width and height to get a different sized window that is custom tailored to fit your content.

I've really only scratched the surface of what you can do with information popups. I encourage you to seek out unique applications of your own—just keep in mind that the main benefit is being able to display small nuggets of HTML content in temporary windows, as opposed to opening entirely new Web pages as traditional links.

Note

Knowing that the size of the information popup window doesn't change once you first initialize it, it's a good idea to try and make all of your content files roughly the same size. That way, they can all be displayed in a single popup window with minimal scrolling. Ideally, there shouldn't be any scrolling, but that's difficult to guarantee across all browsers.


ch09lev1sec6.html

Summary

This chapter tackled an area of Ajax development that is both popular and controversial. Although popup windows are legitimately despised when used inappropriately, they can also be quite helpful when used discretely and for a meaningful purpose. Ajax-powered popup windows are even more interesting than standard popups because they allow you to dynamically load bite-size data from a server instead of having to open an entirely new Web page. This chapter guided you through the development of a sample application that uses the information popup window support built in to the book's Ajax Toolkit. Hopefully you enjoyed working with information popups because this isn't quite the last you'll see of them.


ch10.html

Chapter 10. Forecasting the Weather with Ajax

Ajax the Other Warrior

If you think Ajax the Greek warrior was tough, what about Ajax the New York street thug? In the 1979 movie The Warriors, Ajax was the name of a particularly aggressive street gang member who was always up for a fight. If that doesn't sound scary enough, then maybe his fingerless leather gloves and black tank top will scare your sense of fashion!

Although it can make for mundane conversation in the real world, weather serves as fairly interesting data in the realm of Web services. Weather is a great example of live Web services because it has a very up-to-the-minute feel about it. It's always changing and hard to predict, making it the perfect type of data for live viewing. And weather impacts all of our lives in a very real way, making it a practical information source that is valuable in some Web applications.

This chapter delves into an application that uses Ajax to query a weather server for live weather data, and then displays the weather data in an interesting way. More specifically, the weather data is displayed in a temporary popup window similar to the one shown in Chapter 9, "Presenting Information with Slick Popups." Weather data is ideal for display within a popup because it is concise and often supplementary to the focus of a particular page. In other words, it's the kind of thing you may want to get a quick look at and then dismiss.

The following files are used by the Forecaster application in this chapter, and are located on the live Linux CD-ROM with the book in the chap10 example code folder:

  • forecaster.html— Main Web page

  • forecaster.php—Server script for loading a weather forecast

  • ajaxkit.js—Core Ajax functions for the Ajax Toolkit

  • domkit.js—DOM-related functions for the Ajax Toolkit

  • infowinkit.js—Information window-related functions for the Ajax Toolkit

  • infowinkit.css—Style sheet for information windows

  • infowinkit_wait.gif—Animated "loading" icon that is displayed while loading information into an info window

The Challenge: Gathering Dynamic Weather Information

This chapter's challenge involves using Ajax to dynamically load weather data for a given location. Live weather information might be useful in all kinds of scenarios: a travel Web site, a sports Web site, really any Web site where weather could feasibly have an impact on the site's content. I personally like the idea of a travel Web site because weather happens to play such a critical role in travel decisions. Maybe you're trying to carefully dodge a storm in the tropics during hurricane season, or maybe you want to check for cold enough weather before embarking on a ski trip early in the season. Just about any Web site that deals with travel could benefit from live weather data.

But it's already possible to get weather conditions very easily, so why bother with Ajax and popup windows? Just go to the Weather.com Web site and check out the current weather conditions for any city in the world.

Although Weather.com can't be beaten in terms of the quality of the information it presents, keep in mind that you are required to navigate to it in your browser and then enter the location for the weather report you want. This is a problem if you'd rather not lose the context of the page you're viewing and would instead prefer to get a quick weather update without leaving the page. That's where popup windows enter the picture. By displaying weather data in a popup, you allow the user to continue focusing on the task at hand and not distract him or her by leaving the page. Perhaps more importantly, you remove one excuse for navigating away from your Web site.

So your goal isn't to create a richer or more thorough weather alternative than pure weather sites such as Weather.com. Your goal is to inject live weather data into the context of your existing site, thereby adding some useful new content without the user having to leave the comfort of your pages. Information popup windows are the key to displaying weather data without it competing with the main page being viewed.

The Ajax request involved in this challenge must somehow query a weather service for weather data based upon a specific location. As it turns out, a ZIP code is plenty sufficient to identify a location, and therefore becomes a great piece of data to use for querying weather data. The Ajax response then contains weather data that you must somehow process in order to display meaningful weather information in a popup window.


ch10lev1sec1.html

Chapter 10. Forecasting the Weather with Ajax

Ajax the Other Warrior

If you think Ajax the Greek warrior was tough, what about Ajax the New York street thug? In the 1979 movie The Warriors, Ajax was the name of a particularly aggressive street gang member who was always up for a fight. If that doesn't sound scary enough, then maybe his fingerless leather gloves and black tank top will scare your sense of fashion!

Although it can make for mundane conversation in the real world, weather serves as fairly interesting data in the realm of Web services. Weather is a great example of live Web services because it has a very up-to-the-minute feel about it. It's always changing and hard to predict, making it the perfect type of data for live viewing. And weather impacts all of our lives in a very real way, making it a practical information source that is valuable in some Web applications.

This chapter delves into an application that uses Ajax to query a weather server for live weather data, and then displays the weather data in an interesting way. More specifically, the weather data is displayed in a temporary popup window similar to the one shown in Chapter 9, "Presenting Information with Slick Popups." Weather data is ideal for display within a popup because it is concise and often supplementary to the focus of a particular page. In other words, it's the kind of thing you may want to get a quick look at and then dismiss.

The following files are used by the Forecaster application in this chapter, and are located on the live Linux CD-ROM with the book in the chap10 example code folder:

  • forecaster.html— Main Web page

  • forecaster.php—Server script for loading a weather forecast

  • ajaxkit.js—Core Ajax functions for the Ajax Toolkit

  • domkit.js—DOM-related functions for the Ajax Toolkit

  • infowinkit.js—Information window-related functions for the Ajax Toolkit

  • infowinkit.css—Style sheet for information windows

  • infowinkit_wait.gif—Animated "loading" icon that is displayed while loading information into an info window

The Challenge: Gathering Dynamic Weather Information

This chapter's challenge involves using Ajax to dynamically load weather data for a given location. Live weather information might be useful in all kinds of scenarios: a travel Web site, a sports Web site, really any Web site where weather could feasibly have an impact on the site's content. I personally like the idea of a travel Web site because weather happens to play such a critical role in travel decisions. Maybe you're trying to carefully dodge a storm in the tropics during hurricane season, or maybe you want to check for cold enough weather before embarking on a ski trip early in the season. Just about any Web site that deals with travel could benefit from live weather data.

But it's already possible to get weather conditions very easily, so why bother with Ajax and popup windows? Just go to the Weather.com Web site and check out the current weather conditions for any city in the world.

Although Weather.com can't be beaten in terms of the quality of the information it presents, keep in mind that you are required to navigate to it in your browser and then enter the location for the weather report you want. This is a problem if you'd rather not lose the context of the page you're viewing and would instead prefer to get a quick weather update without leaving the page. That's where popup windows enter the picture. By displaying weather data in a popup, you allow the user to continue focusing on the task at hand and not distract him or her by leaving the page. Perhaps more importantly, you remove one excuse for navigating away from your Web site.

So your goal isn't to create a richer or more thorough weather alternative than pure weather sites such as Weather.com. Your goal is to inject live weather data into the context of your existing site, thereby adding some useful new content without the user having to leave the comfort of your pages. Information popup windows are the key to displaying weather data without it competing with the main page being viewed.

The Ajax request involved in this challenge must somehow query a weather service for weather data based upon a specific location. As it turns out, a ZIP code is plenty sufficient to identify a location, and therefore becomes a great piece of data to use for querying weather data. The Ajax response then contains weather data that you must somehow process in order to display meaningful weather information in a popup window.


ch10lev1sec2.html

The Design: Designing a Weather Forecaster

The application you develop to meet the dynamic weather challenge is called Forecaster, and its design heavily revolves around the existing information window support in the infowinkit.js file that is part of the book's Ajax Toolkit. In fact, the Forecaster application is very similar in structure to the Informer application developed in Chapter 9, except it requests live weather information for a particular location as opposed to pre-built HTML content files. Figure 10.1 gives you an idea as to how the user interface of the Forecaster application is structured.

Figure 10.1. The user interface for the Forecaster application consists of a Web page with info links that trigger a popup window containing live weather information.

The figure shows how the Forecaster page consists of standard text with city links sprinkled in. Each city link is actually an info link that results in the display of a popup window containing live weather data. This also means that clicking a city link results in an Ajax request that retrieves the weather data so that it can be displayed in a popup window.

In order for an Ajax weather request to work, you actually need access to live weather data in a structured format such as XML. As it turns out, you can use several weather sources on the Internet to accomplish this task. One service I like is the RSS weather feed made available by Yahoo! Weather. This weather data is made available in the RSS format, which is a specific XML data format that is traditionally used to share news, as was shown in Chapter 5, "Tapping into RSS News Feeds." However, there is no reason an RSS feed can't be used for other types of data, and in this case Yahoo! Weather uses RSS for weather data.

Note

RSS (Really Simple Syndication) is an XML data format designed for representing news stories in a consistent manner. A typical RSS document, or feed, contains multiple news stories with detailed information such as a title, description, publish date, and a link to the article online. The RSS format can actually be used beyond the realm of news, and is in fact useful for any text information that changes on a regular basis. There are numerous third-party applications, called RSS readers, that allow you to view and access multiple RSS feeds in a single view.

Figure 10.2 shows the Yahoo! Weather RSS feed Web page (http://developer.yahoo.com/weather/), which contains excellent documentation on the weather feed and how to customize it to suit your needs.

Figure 10.2. The Yahoo! Weather RSS feed Web page offers a live XML weather feed.

[View full size image]

You learn the basics of how to mine weather data from the Yahoo! Weather feed throughout the rest of the chapter, but feel free to refer back to this Web page to learn more on your own.

Getting back to the design of the Forecaster application, you now have a live weather service that can be used as the basis for Ajax weather requests. Each of these requests is made as a result of the user clicking a city in the Web page text, which happens to be an info link. This means that when a city is clicked, an information window is displayed that contains weather data obtained through an Ajax request made on the Yahoo! Weather server. The next few sections explore this Ajax request in a bit more detail.

The Client Request

If you've been progressing through this book sequentially, you may already be thinking that the Ajax request for the weather data is going to require a server-side script in order to deal with the security limitation of not being able to request data from a remote server. In this case the Yahoo! Weather server certainly qualifies as a remote server. You therefore need a PHP script to serve as somewhat of a proxy for carrying out the actual Yahoo! Weather request from the server instead of the client.

Aside from the PHP script on the server, the client request in the Forecaster application is not too messy because the only information it must pass along to the server is the ZIP code of the desired location. The ZIP code is used to identify a location, and the Yahoo! Weather service fortunately is able to look up weather information based solely on a ZIP code. The resulting Ajax client request therefore involves a PHP server script with a ZIP code parameter.

The Server Response

The response to the weather request comes in the form of an RSS document full of useful weather data. If you recall, the RSS format is an XML data format, which means you can extract data from it based upon tag names without too much trouble. This is important because you won't be using all of the information returned in the Ajax response.

As you see in the next section, the standard Ajax response delivered by the Yahoo! Weather service contains much more information than is needed for this particular example. For this reason, you need to be able to pluck out specific information using the server script and only return that information to the client. The server script is already a necessity given the security workaround mentioned earlier, so adding a little more code to extract specific weather data won't present too much of a challenge.

Making Sense of the Client-to-Server Conversation

You now understand enough about the role of the client and server in the Forecaster application to visualize a single Ajax weather request and its associated response. Figure 10.3 shows the client-to-server conversation taking place with respect to this request.

Figure 10.3. The Forecaster application involves sending a ZIP code from the client and receiving HTML weather content from the server.

The figure reveals how the Ajax request generates a response that relays weather content back to the browser (client). I'm careful to refer to this weather information as "content" as opposed to "data" because there is a subtle difference. "Data" usually refers to raw information that hasn't been coded or formatted in any particular way, whereas "content" often refers to data that has somehow been processed. In this particular case, the weather information is classified as content because it is returned from the server as HTML code that is ready to be displayed in a popup window.

Getting back to the Ajax request shown in the figure, you pass the ZIP code for a location along with the Ajax request by packaging it into a URL as a single parameter. Here's an example of a URL used to pass along a ZIP code to the PHP script for the Forecaster application:

forecaster.php?zipCode=37205

This code reveals that the PHP script responsible for handling the Ajax weather request is in the file named forecaster.php. This script is responsible for retrieving the RSS weather data from the Yahoo! Weather server, extracting only the weather information desired, and then returning this information to the client. You find out exactly how this script works such weather magic later in the section titled, "The Forecaster Server Script."

The weather data returned from the server is actually much more detailed than is needed for the Forecaster application, which is why the server script only extracts a portion of the data to be returned to the client. It just so happens that the Yahoo! Weather service offers a preformatted chunk of weather information that can easily be accessed separately from the remaining weather data. This chunk is formatted as HTML code that is ready to be displayed in a popup window. Following is an example of what this code looks like:

<img src="http://us.i1.yimg.com/us.yimg.com/i/us/we/52/30.gif"/>
<br />
<b>Current Conditions:</b><br />
Partly Cloudy, 66 F<br /><br />
<b>Forecast:</b><br />
Wed - Partly Cloudy. High: 69 Low: 42<br />
Thu - Sunny. High: 61 Low: 32<br /><br />
<a href="http://weather.yahoo.com/forecast/37205_f.html">
  Full Forecast at Yahoo! Weather</a><br />
(provided by The Weather Channel)<br />

As you can see, this code is already formatted for display thanks to several HTML tags.

The preformatted weather information is identified in the main RSS weather feed using the <description> tag. In other words, the code you just saw is enclosed between <description> and </description> tags within the RSS XML code. Following is an abbreviated RSS weather feed document that shows how the <description> tag is used:

Code View:
<rss version="2.0"
xmlns:yweather="http://xml.weather.yahoo.com/ns/rss/1.0"
  xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#">
  <channel>
    <title>Yahoo! Weather - Nashville, TN</title>
    <link>http://weather.yahoo.com/forecast/37205_f.html</link>
    <description>Yahoo! Weather for Nashville, TN</description>
    ...
    <item>
      <title>Conditions for Nashville, TN at 10:53 am CST</title>
      <geo:lat>36.11</geo:lat>
      <geo:long>-86.68</geo:long>
      ...
      <description><![CDATA[
        <img src="http://us.i1.yimg.com/us.yimg.com/i/us/we/52/
          30.gif" /><br />
        <b>Current Conditions:</b><br />
        Partly Cloudy, 66 F<br /><br />
        <b>Forecast:</b><br />
        Wed - Partly Cloudy. High: 69 Low: 42<br />
        Thu - Sunny. High: 61 Low: 32<br /><br />
        <a href="http://weather.yahoo.com/forecast/37205_f.html">
          Full Forecast at Yahoo! Weather</a><br />
        (provided by The Weather Channel)<br />
      ]]></description>
      ...
    </item>
  </channel>
</rss>

This code reveals how the <description> tag is embedded down in the RSS code for the weather feed, and how it stores away an HTML-encoded version of the weather information. The job of the Forecaster server script is just to pluck out the contents of the <description> tag and return them to the client as the Ajax response.


ch10lev1sec3.html

Putting Together the Forecaster Application

In addition to the support features provided by the Ajax Toolkit, such as the information popup window, the Forecaster application consists of two components:

  • HTML Web page (forecaster.html)

  • PHP server script (forecaster.php)

The next two sections examine these pieces of the Forecaster puzzle in more detail. Hopefully you already have a decent idea as to what they do, and possibly even how they do it.

The Forecaster Web Page

The HTML Web page for the Forecaster application consists of a paragraph of text with weather info links (cities) sprinkled throughout. The page is deceptively simple in terms of not having any input controls. However, a click of the mouse on any of the linked cities reveals that there is more to Forecaster than initially meets the eye. Figure 10.4 shows a quick preview of the user interface, which will help you understand the HTML code required to make it possible.

Figure 10.4. The Forecaster Web page consists of a paragraph of text with info links used to connect cities to their respective live weather information.

[View full size image]

Following is the HTML code behind the page (forecaster.html) shown in the figure:

Code View:
<body onload="initInfoWindow(300, 240)">
  <div id="ajaxState" style="display:none"></div>
  <br />
  <h2>Forecaster - Traveling the U.S.</h2>
  <p>A great way to get the full cultural experience of
    traveling is to hit the road and cover as much terrain as
    possible. Within the U.S., it is possible to experience the
    full range of climates, which can often make planning
    difficult in terms of preparing for different kinds of
    weather.
    For example, let's say you start your trip in <a href="#"
    class="info" onclick="return showInfoWindow(
    'forecaster.php?zipCode=10001', event)">New York City</a>
    with the plan of crossing the country and finishing in
    <a href="#" class="info" onclick="return showInfoWindow(
    'forecaster.php?zipCode=94129', event)">San Francisco</a>.
    Depending upon the time of year, you will experience quite a
    variety of different weather. If your trip cuts deep into
    the south, you'll come to understand why <a href="#"
    class="info" onclick="return showInfoWindow(
    'forecaster.php?zipCode=30301', event)">Atlanta</a> is
    affectionately known as Hotlanta. Cruising west, you'll need
    to keep your eyes peeled for tornadoes as you pass through
    <a href="#" class="info"
    onclick="return showInfoWindow(
    'forecaster.php?zipCode=73101', event)">Oklahoma City</a>.
    If you thought Atlanta was hot, your stop off in
    <a href="#" class="info" onclick="return showInfoWindow(
    'forecaster.php?zipCode=85003', event)">Phoenix</a> will
    quickly let you know why they call it the Valley of the Sun.
    Traveling northward to get a break from the heat, a stop off
    in <a href="#" class="info" onclick="return showInfoWindow(
    'forecaster.php?zipCode=80012', event)">Denver</a> at the
    foot of the Rockies is sure to energize you for the final
    push toward California.
  </p> </body>

The first line of code gets busy with the very important task of initializing the information popup window and establishing its default size (300x240). The remaining code in the page creates the paragraph of text and defines the weather info links. Because the info links are embedded directly in the paragraph of text, and are therefore a bit hard to make out, take a look at one of the links by itself:

<a href="#" class="info"
 onclick="return showInfoWindow('forecaster.php?zipCode=94129',
 event)">San Francisco</a>

This link is used to launch a popup window containing current weather information for the ZIP code 94129, which is located in San Francisco, California. Notice that the ZIP code is provided as a parameter (zipCode) to the forecaster.php server script. The entire URL for the server script and ZIP code is passed into the showInfoWindow() function, which is the Ajax Toolkit function used to display an information popup window.

Although the body of the Forecaster Web page is where the interesting stuff happens, the head of the page is also important because it imports the needed JavaScript and CSS files. Following is the head of the page:

<head>
  <title>Forecaster</title>

  <link rel="stylesheet" type="text/css" href="infowinkit.css" />
  <script type="text/javascript" src="ajaxkit.js"> </script>
  <script type="text/javascript" src="domkit.js"> </script>
  <script type="text/javascript" src="infowinkit.js"> </script>
</head>

The CSS file and three JavaScript files are all part of the book's Ajax Toolkit, which provides numerous helpful Ajax functions.

The Forecaster Server Script

Because the weather information in the Forecaster application is ultimately loaded from a remote server (Yahoo! Weather), you can't issue an Ajax request directly from the client. The Forecaster server script is necessary in order to circumvent this restriction and access information on a remote server. Not only that, but the server script plays an additional role in that it must extract a specific portion of the weather data and only return that data to the client. In other words, the client doesn't need the entire contents of the Yahoo! Weather feed.

The Forecaster PHP server script expects to be passed a ZIP code that it can then use to request weather data for a specific location. Following is the code for the forecaster.php server script:

<?php
header('Content-Type: text/xml');

// Parse the XML weather data into a structure
$rawFeed =
file_get_contents("http://weather.yahooapis.com/forecastrss?p=" .
  $_REQUEST["zipCode"]);
$xml = new SimpleXmlElement($rawFeed);
echo "<div>" . $xml->channel->item->description . "</div>";
?>

Remember that the job of this script is to retrieve an XML (RSS) document from the Yahoo! Weather service, extract the content within the <description> tag, and then pass that HTML code along to the client. All the client has to do is display the HTML weather code in a popup. In actuality, the client delegates these details to the information popup window support in the Ajax Toolkit.

The server script begins by making sure that the response gets treated as XML. The second chunk of code in the script then loads the RSS/XML weather document from the weather service, making sure to pass along the zipCode parameter so that the service knows the weather location. The raw XML data returned by the weather service is then converted to a structured XML object so that you can easily access individual elements.

The last section of code is where the weather information is actually returned from the script, which serves as the response to the Ajax weather information request. The formatted HTML weather code is wrapped inside an HTML div element before being returned to the client.

Before moving on to test the completed Forecaster application, it's important to first test the PHP script by itself. You've seen this done in previous chapters, but it never ceases to be an important step in any Ajax application that involves a custom server script. Following is a sample URL for testing the Forecaster script:

http://www.yourdomain.com/forecaster.php?zipCode=94129

Assuming the forecaster.php file is stored on your server, change the domain to match yours in this line of code and then enter the URL into your Web browser. You can also try this trick directly on the live CD that accompanies this book. Regardless of where you access the script from, Figure 10.5 shows the HTML response data generated by the PHP script.

Figure 10.5. You can examine the HTML weather information returned by the Forecaster PHP script by opening the script directly in a browser.

[View full size image]

Feel free to experiment with different ZIP codes in the URL for the Forecaster script. This is a great way to study the data returned by a server script to make sure it is consistent with what you expected—server script problems are much more difficult to track down when you're limited to looking at everything through the eyes of the client Web page.


ch10lev1sec4.html

Testing Forecaster

It requires a great deal of skill and patience to test the Forecaster application. That is, of course, assuming that you consider clicking the mouse a few times a difficult job. Seriously, this is a very easy application to test out because all you have to do is click a few links on the page. Figure 10.6 shows how the Forecaster application starts out with the weather popup window hidden from view.

Figure 10.6. The Forecaster application starts off with the weather popup window hidden from view because no cities have been clicked yet.

[View full size image]

Notice in this figure how nothing weather-related appears on the page, meaning that the weather doesn't distract in any way from the main content. This is important because the weather is intended to be supplemental and voluntary—readily available but visible at the user's discretion.

Clicking a city (weather link) results in the display of a weather popup window with the local weather conditions for the city. But keep in mind that the weather data is being loaded from a remote Web service, which doesn't always take place instantaneously. Figure 10.7 shows how an animated "loading" icon appears while the weather information is being loaded.

Figure 10.7. When a link on the page is clicked, an animated "loading" icon appears during the loading of the weather information.

[View full size image]

Unless you're using an antique dial-up modem or the Yahoo! Weather service is experiencing delays, you'll see the weather data for Denver, Colorado, pretty quickly, as shown in Figure 10.8.

Figure 10.8. The dynamically loaded weather information for Denver is displayed in an information popup window.

[View full size image]

The weather information for Denver is loaded and displayed in an information popup window that floats over the main Forecaster page. This allows you to quickly view the weather without having to actually navigate away from the page. When you're finished viewing the weather, just click anywhere on the popup window and it will disappear.

Getting the weather conditions for another city is as simple as clicking the city's name (info link). Figure 10.9 shows the weather for Atlanta, Georgia, being displayed in a popup.

Figure 10.9. The weather conditions for Atlanta, Georgia, are as readily accessible as those for Denver or any of the other cities on the page.

[View full size image]

So maybe 61 degrees Fahrenheit really isn't a justification for the name Hotlanta, but you have to consider that we're talking about February here. Just check back with the Forecaster application in July and you'll see what I'm talking about.


ch10lev1sec5.html

Giving Forecaster an Extreme Ajax Makeover

The quickest and simplest way to make over the Forecaster application is to try out some different cities. For example, change one of the cities in the Web page to your own hometown, making sure to replace the ZIP code with your own ZIP code in the info link for the city. More specifically, be sure to change the URL passed into the showInfoWindow() function so that it references your ZIP code. As an example, if your ZIP code is 92024 (Encinitas, CA), you'll want to change the showInfoWindow() function in the info link onclick event handler to this:

onclick="return showInfoWindow('forecaster.php?zipCode=92024',
  event)"

The info link will then pass along your ZIP code to the weather server when requesting weather data, and will therefore display your own local live weather conditions in the information popup window.

If you have some PHP and JavaScript skills and want to go for a more extreme makeover of the Forecaster application, you might want to consider drilling down into the RSS weather data returned by Yahoo! Weather. The Forecaster application currently takes advantage of the fact that the Yahoo! RSS feed includes a <description> tag that provides a clean, HTML-friendly weather view. The feed actually includes quite a bit more information, giving you plenty of freedom in customizing a more detailed weather view if you so desire.

As an example, the following fields can be accessed within the Yahoo! Weather feed to get information that doesn't appear in the <description> tag:

<wind chill="57" direction="230" speed="7" />
<atmosphere humidity="72" visibility="1609" pressure="30.22"
  rising="0" />
<astronomy sunrise="6:28 am" sunset="5:38 pm" />

Here, you see the wind chill, wind direction, and wind speed in the first <wind> tag. The second tag (<atmosphere>) addresses atmospheric conditions such as humidity, visibility, barometric pressure, and how much the pressure is either rising or lowering. And finally, the third tag (<astronomy>) provides the sunrise and sunset times for the location. To help make sense of the first two tags, another tag specifies the units for the weather data:

<units temperature="F" distance="mi" pressure="in" speed="mph" />

This line of code lets you know that all temperatures are expressed in degrees Fahrenheit, distances are in miles, barometric pressures are in inches, and wind speeds are in miles per hour. When assembling a custom view of the weather data, you can pluck out these units and append them to the weather values to provide additional detail and give the values more meaning.


ch10lev1sec6.html

Summary

You already are no doubt aware of the fact that there are numerous sources on the Web for getting live weather information for pretty much any location on the planet. What isn't so easily done is closely tying such information to your own pages in a manner that doesn't take away from the user's experience. Information popup windows provide a nifty mechanism for displaying weather data within the context of your pages without requiring the user to navigate away from them. The Forecaster application serves as a good demonstration of how straightforward it is to include location-specific live weather data in a page of your own.


ch11.html

Chapter 11. Building an Ajax Shipping Calculator

Ajax at High Altitude

If you're into ritzy skiing, you may be familiar with Ajax as it applies to mountains. Situated immediately to the south of the posh town of Aspen, Colorado, Aspen Mountain is home to the Aspen/Snowmass ski areas. Locals sometimes refer to Aspen Mountain as Ajax.

Don't you get tired of the part of the online shopping experience where you're interested in buying something but you need to know the shipping costs in order to determine whether it's really a deal? Problem is, most shopping carts don't clue you in on the shipping charge until the very last step of the checkout process, after you've entered your name, address, date of birth, mother's maiden name, favorite childhood pet, and whatever other personal data they can get from you before finalizing the purchase. Wouldn't it be nice to get the shipping charge early on in the checkout process, definitely before entering your credit card information, and preferably without a page reload? As you might be guessing, Ajax offers a better way.

This chapter solves the shipping charge problem by showing you how to use Ajax to dynamically determine a shipping charge without the user even realizing it. Not only that, but the shipping charge is obtained directly from the U.S. Postal Service shipping charge Web service, which means you aren't guessing or dealing with potentially outdated lookup tables—you're getting the information directly from the source. The Shipper sample application in this chapter shows conclusively how Ajax can elegantly solve a common problem and sneakily improve the feel of any Web application that involves the calculation of shipping charges.

The following files are used by the Shipper application in this chapter, and are located on the live Linux CD-ROM with the book in the chap11 example code folder:

  • shipper.html—Main Web page

  • shipper.php—Server script for loading a shipping charge

  • ajaxkit.js—Core Ajax functions for the Ajax Toolkit

  • domkit.js—DOM-related functions for the Ajax Toolkit

  • wait.gif—Animated "loading" icon that is displayed while loading a shipping charge

The Challenge: Retrieving Live Shipping Charges

The challenge in this chapter is simple in theory but somewhat tricky in practice. The trickiness arises from the fact that the Web service used to obtain shipping charge information isn't as trivial to access as some of the other Web services you've seen throughout the book. More specifically, the Shipper application in this chapter uses the U.S. Postal Service Web Tools to retrieve shipping charges. The problem arises from the fact that the USPS Web service requires you to submit a fairly detailed XML document in order to obtain a shipping charge.

Of course, this shouldn't be too surprising when you consider that several pieces of information are involved in determining how much it costs to ship an item. You have the origin and destination locations (ZIP codes), plus specifics about the item itself, such as its size and weight. And then you have to choose from several possible shipping options, such as Parcel Post or Priority Mail. All of this information must be carefully tucked away into an XML document that the USPS Web service understands.

To give the Shipper application a practical feel, its user interface simulates a shopping cart where you've already selected a specific item for purchase and are ready to check out. To keep things simple, however, you aren't providing control over the contents of the shopping cart. In other words, the Shipper application focuses solely on accepting destination shipping information so that it can dynamically calculate the shipping charge. Building a fully functioning shopping cart is a bit beyond the scope of this chapter.

Even though the contents of the shopping cart can't be manipulated by the user in the Shipper application, the destination ZIP code and shipping method are both changeable. And this gets us to where Ajax enters the picture. Any time the ZIP code or shipping method changes, an Ajax request is made on the USPS Web service to grab a new shipping charge and update the cart. You're able to update the cart thanks to the fact that the application already knows how much the item in the cart costs. So it's merely a matter of adding the item price to the shipping charge to display a total for the shopping cart.

Again, even though the application gives the illusion of a fully functioning shopping cart, all it's really doing is using static shopping cart data combined with dynamic shipping information (ZIP code and shipping method) to obtain a shipping charge via Ajax and update the total price of the transaction. This keeps the challenge tightly focused on the subject at hand—using Ajax to dynamically retrieve a shipping charge from the USPS Web service.


ch11lev1sec1.html

Chapter 11. Building an Ajax Shipping Calculator

Ajax at High Altitude

If you're into ritzy skiing, you may be familiar with Ajax as it applies to mountains. Situated immediately to the south of the posh town of Aspen, Colorado, Aspen Mountain is home to the Aspen/Snowmass ski areas. Locals sometimes refer to Aspen Mountain as Ajax.

Don't you get tired of the part of the online shopping experience where you're interested in buying something but you need to know the shipping costs in order to determine whether it's really a deal? Problem is, most shopping carts don't clue you in on the shipping charge until the very last step of the checkout process, after you've entered your name, address, date of birth, mother's maiden name, favorite childhood pet, and whatever other personal data they can get from you before finalizing the purchase. Wouldn't it be nice to get the shipping charge early on in the checkout process, definitely before entering your credit card information, and preferably without a page reload? As you might be guessing, Ajax offers a better way.

This chapter solves the shipping charge problem by showing you how to use Ajax to dynamically determine a shipping charge without the user even realizing it. Not only that, but the shipping charge is obtained directly from the U.S. Postal Service shipping charge Web service, which means you aren't guessing or dealing with potentially outdated lookup tables—you're getting the information directly from the source. The Shipper sample application in this chapter shows conclusively how Ajax can elegantly solve a common problem and sneakily improve the feel of any Web application that involves the calculation of shipping charges.

The following files are used by the Shipper application in this chapter, and are located on the live Linux CD-ROM with the book in the chap11 example code folder:

  • shipper.html—Main Web page

  • shipper.php—Server script for loading a shipping charge

  • ajaxkit.js—Core Ajax functions for the Ajax Toolkit

  • domkit.js—DOM-related functions for the Ajax Toolkit

  • wait.gif—Animated "loading" icon that is displayed while loading a shipping charge

The Challenge: Retrieving Live Shipping Charges

The challenge in this chapter is simple in theory but somewhat tricky in practice. The trickiness arises from the fact that the Web service used to obtain shipping charge information isn't as trivial to access as some of the other Web services you've seen throughout the book. More specifically, the Shipper application in this chapter uses the U.S. Postal Service Web Tools to retrieve shipping charges. The problem arises from the fact that the USPS Web service requires you to submit a fairly detailed XML document in order to obtain a shipping charge.

Of course, this shouldn't be too surprising when you consider that several pieces of information are involved in determining how much it costs to ship an item. You have the origin and destination locations (ZIP codes), plus specifics about the item itself, such as its size and weight. And then you have to choose from several possible shipping options, such as Parcel Post or Priority Mail. All of this information must be carefully tucked away into an XML document that the USPS Web service understands.

To give the Shipper application a practical feel, its user interface simulates a shopping cart where you've already selected a specific item for purchase and are ready to check out. To keep things simple, however, you aren't providing control over the contents of the shopping cart. In other words, the Shipper application focuses solely on accepting destination shipping information so that it can dynamically calculate the shipping charge. Building a fully functioning shopping cart is a bit beyond the scope of this chapter.

Even though the contents of the shopping cart can't be manipulated by the user in the Shipper application, the destination ZIP code and shipping method are both changeable. And this gets us to where Ajax enters the picture. Any time the ZIP code or shipping method changes, an Ajax request is made on the USPS Web service to grab a new shipping charge and update the cart. You're able to update the cart thanks to the fact that the application already knows how much the item in the cart costs. So it's merely a matter of adding the item price to the shipping charge to display a total for the shopping cart.

Again, even though the application gives the illusion of a fully functioning shopping cart, all it's really doing is using static shopping cart data combined with dynamic shipping information (ZIP code and shipping method) to obtain a shipping charge via Ajax and update the total price of the transaction. This keeps the challenge tightly focused on the subject at hand—using Ajax to dynamically retrieve a shipping charge from the USPS Web service.


ch11lev1sec2.html

The Design: Designing a Shipper Application

Because the Shipper application is attempting to simulate a shopping cart, some of its user interface elements are purely for decoration and don't directly impact the functionality. Figure 11.1 shows a sketch of the application's user interface, along with which fields play a direct role in the retrieval and display of shipping charge information.

Figure 11.1. The user interface for the Shipper application includes fields for entering a ZIP code and viewing the resulting shipping charge, among others.

The figure shows several input fields, but only two of them, ZIP code and Shipping method, directly impact the calculation of the shipping charge. This shipping charge calculation involves submitting the ZIP code, shipping method, and other details about the item being shipped to the USPS Web service for domestic shipping rates. Upon successfully retrieving the shipping charge from the USPS server, the Shipper application calculates an order total by adding the item price to the shipping charge.

Because it is certainly possible for the user to enter a ZIP code that is invalid, and therefore won't result in a shipping charge, a help text display field next to the ZIP code is used to let the user know whether a problem exists with the ZIP code. This field gets set if the server returns a shipping charge of 0, which indicates that there was a problem with the ZIP code.

Another subtle touch to the Shipper application that isn't revealed in the figure is the usage of an animated "loading" image to indicate the status of the Ajax request. This image appears in place of the shipping charge while the charge is being looked up on the USPS server. Figure 11.2 shows what this small image, wait.gif, looks like.

Figure 11.2. The Shipper application makes use of a small animated "loading" image (wait.gif) to let the user know the Ajax request is being processed.

Because the user may still be busy entering information while the shipping charge request is being processed, it isn't imperative to make the "loading" image prominent on the page. That's why it appears in place of the shipping charge. Of course, this means the shipping charge field performs double duty, but that doesn't pose a problem. Just know that the field holds the actual shipping charge when a request isn't taking place, and it displays the "loading" image during a request.

Despite the considerable number of input fields in the Shipper application's user interface, keep in mind that only two of them (ZIP code and shipping method) directly play into the shipping charge Ajax request. And only a couple of other fields (Shipping charge and Order total) factor into the resulting display of the requested shipping charge information.

So even though the application looks fairly involved, it is really only dealing with one Ajax request, which helps to simplify things considerably. You're now ready to learn a little more about the shipping charge Ajax request.


ch11lev1sec3.html

The Client Request

The client request for the Shipper application is one of the trickier Ajax requests you encounter in the book because it is responsible for passing along a fair amount of information to the server. Before getting into the details of that information, however, let's quickly address the fact that we're dealing with a remote Web server.

As you'll recall from numerous other sample applications, it isn't possible to issue an Ajax request directly on a third-party (remote) Web server for security reasons. The way around this limitation is to use your own server script as the basis for forwarding along the request to the remote server, which is allowed because server-to-server communication is considered perfectly legit. As it turns out, a server script is needed in this case for reasons beyond the Ajax security limitation, so you'd be dealing with a PHP script anyway.

I've mentioned already that the Shipper application only needs to pass along the ZIP code and shipping method in order to obtain a live shipping charge from the USPS Web server. Although this may be true from the perspective of the application, it isn't true at all from the perspective of the USPS. Considerably more information is needed in order to determine how much it costs to mail an item. More specifically, the following information is needed by the USPS Domestic Rates Web service in order to successfully return a shipping charge:

  • User ID

  • Password

  • Shipping method

  • Origin ZIP code

  • Destination ZIP code

  • Weight of item (pounds)

  • Weight of item (ounces)

  • Container type

  • Size

  • Machinable (within normal package limitations)

The first two pieces of information are the user ID and password for your USPS Web Tools account, which are necessary in order to even test the Shipper application. In fact, you'll have to obtain your own user ID before you can even run the application. Like I said earlier, the USPS is much stricter about allowing access to its Web services than other services you've encountered throughout the book. In turn, you'll be able to safely reference your USPS user ID and password from a server script, as opposed to a client Web page, which provides an added measure of security for the Shipper application.

Note

For testing purposes, you'll likely just be assigned a user ID and no password, meaning that you can leave the password blank when issuing a shipping rate request.

You should have a decent feel for the next pieces of information because we've already talked a fair amount about the shipping method and ZIP codes. However, it is worth pointing out that the Shipper application hard-codes the origin ZIP code to a test ZIP code required by the USPS for testing. In a production environment, you'll change this ZIP code to the ZIP code from which you'll be sending packages.

Note

When I say the application "hard-codes" a piece of information, I simply mean that the application sets the information internally instead of allowing the user to select it or enter it. This is primarily a simplification in the case of the Shipper application, although some of the hard-coded information is unlikely to change even in a production application.

The two weights passed along to the USPS Web service are necessary to break down a package weight into its different unit components. These weights are used together, meaning that a package that weighs 4 pounds 3 ounces results in a "pounds" value of 4 and an "ounces" value of 3. In other words, it doesn't mean that you provide the total weight in different units. As another example, if a package weighs 6 pounds 0 ounces, then the "pounds" value is 6 and the "ounces" value is 0. The Shipper application again hard-codes these values because it is only simulating a shopping cart and assumes that you've already selected an item at this point in the checkout process.

The container type describes the container that houses the package, and for testing purposes must be set to "Flat Rate Box." Although you might want to incorporate other container types into a production application, Flat Rate Box covers an awful lot of packages. This is another piece of information that is hard-coded in the Shipper application.

The size of the package must correspond to one of the standard package size designations imposed by the USPS. For testing purposes, you must set the package size to "Large." Not surprisingly, this piece of information is hard-coded in the Shipper application.

The last thing you need to pass along to the USPS Web service is whether or not the package is "machinable," which refers to whether or not the package fits within certain predictable constraints. Nonmachinable packages include extremely large packages, irregularly shaped containers, and other scenarios where you aren't shipping a reasonably sized flat- or box-shaped container. For testing purposes, you must specify that the package is machinable. I'm sure you guessed it—the machinable piece of request information is hard-coded in the Shipper application.

I don't expect you to commit to memory the different pieces of information required for a USPS shipping rate Ajax request. You see them again in a moment when you explore the specific XML code used to format them for the USPS server.


ch11lev1sec4.html

The Server Response

Just as the USPS Domestic Rates Web service expects an XML document as the basis for calculating a shipping rate, it also returns the rate in the form of an XML document. In fact, it is typically used to return several shipping rates at once, in which case it is the job of the application processing the request to pluck out whatever specific rates are needed. In the case of the Shipper application, it is the job of the PHP server script to receive the USPS XML response data and sift through it to find the desired shipping rate.

The next section digs much deeper into the data passed back and forth with the USPS Domestic Rates Web service, including the specific XML data sent back as the USPS server response.


ch11lev1sec5.html

Making Sense of the Client-to-Server Conversation

The Ajax request within the Shipper application is used to shuttle a user-entered ZIP code and shipping method to the server, along with several other fixed pieces of USPS shipping information. In return, the PHP server script returns to the Shipper client Web page a single shipping charge. Figure 11.3 helps to clarify this transfer of data visually.

Figure 11.3. The Shipper application involves several pieces of shipping information being sent to the server and a single shipping rate returned to the client.

It's very important before we move any further into the details of the Shipping application to clarify that you are required to test any application that uses the USPS Web Tools on a USPS test server before being allowed to use a production server. In practical terms, this means that you are limited to a very specific set of test data for use while testing your application. This means that the test data you're about to see for the Shipper application is not arbitrary—it is provided specifically by the USPS for use with its test server.

Note

If you deviate from the standard USPS test data while still using the USPS test server, the Shipper application will not work. You can't try out a full range of test data (ZIP codes) until you become validated by the USPS and gain access to its production server. You find out more about how to get validated later in the chapter in the "Giving Shipper an Extreme Ajax Makeover" section.

The test data imposed by the USPS even limits you to using a specific origin ZIP code and a specific destination ZIP code. Following is an example of an Ajax request URL that uses the standard USPS test data set to retrieve shipping rate data for the Shipper application:

shipper.php?userID=YOURUSPSUSERID&origZip=10022&destZip=20008&
weightLb=10&weightOz=5&container=Flat%20Rate%20Box%20&
size=Large&mailService=Priority%20Mail

First off, understand that this is one long URL, even though it is broken across several lines on the page. All of the information should be at least vaguely familiar because you've already learned about the pieces required for a USPS Domestic Rates shipping request. One thing I haven't fully explained is the user ID, which you'll notice is set to YOURUSPSUSERID. You may have also noticed that no password is specified in the URL. What gives?

In order to access the USPS Web Tools, you are required to have your own user ID that is issued to you by the USPS, which is very strict about the sharing of user IDs. This is why I couldn't just print mine here for you to use. So, before you go any further, I encourage you to register (for free) for your own USPS Web Tools user ID at http://www.usps.com/webtools/. After obtaining this ID you'll be able to plug it into the URL you just saw to complete a Shipper Ajax request URL.

During the testing phase of a USPS Web services application, it isn't necessary to provide a password, which is why a password isn't specified in the URL. In a production environment, you would certainly use a password; the shipper.php server script accepts a password via the password parameter in the request URL.

It's important at this point to distinguish between the Ajax request URL that is issued on your server and the USPS request URL that is issued on the USPS server. The former URL is used to pass data along to your shipper.php server script, whereas the latter is used within your shipper.php server script to carry out the actual shipping rate query on the USPS server. So, the shipper.php script resides on your server, and is responsible for accepting shipping parameters via a URL and then using them to build another URL that passes along a query to the USPS server.

You just saw the URL for the Ajax request, so now let's turn our attention to the USPS request, which expects the shipping information to be formatted in XML:

http://testing.shippingapis.com/ShippingAPITest.dll?API=RateV2&
XML=<RateV2Request%20USERID="YOURUSPSUSERID"%20PASSWORD="">
<Package%20ID="0"><Service>All</Service><ZipOrigination>10022
</ZipOrigination><ZipDestination>20008</ZipDestination><Pounds>
10</Pounds><Ounces>5</Ounces><Container>Flat%20Rate%20Box
</Container><Size>Large</Size><Machinable>true</Machinable>
</Package></RateV2Request>

Yikes! I know you're thinking that is some messy looking XML code. And when crammed together in the form of a URL, it certainly is. But let's add some line breaks and tabs to show it in a more traditional XML view:

http://testing.shippingapis.com/ShippingAPITest.dll?API=RateV2&
XML=
<RateV2Request USERID="YOURUSPSUSERID" PASSWORD="">
  <Package ID="0">
    <Service>All</Service>
    <ZipOrigination>10022</ZipOrigination>
    <ZipDestination>20008</ZipDestination>
    <Pounds>10</Pounds>
    <Ounces>5</Ounces>
    <Container>Flat Rate Box</Container>
    <Size>Large</Size>
    <Machinable>true</Machinable>
  </Package>
</RateV2Request>

Now the USPS request URL should make a bit more sense. All that's going on is that the Ajax request data has now been formatted into an XML document that adheres to the USPS Domestic Rates request format. The only two pieces of information that don't map directly to data that you've passed along are the <Service> and <Machinable> tags, which are used to indicate that you want the shipping rates for all shipping methods (services) and that the package is indeed machinable (nothing unusual in terms of packaging).

Upon this request being issued to the USPS server, a different XML document is sent back in return:

Code View:
<RateV2Response>
  <Package ID="0">
    <ZipOrigination>10022</ZipOrigination>
    <ZipDestination>20008</ZipDestination>
    <Pounds>10</Pounds>
    <Ounces>5</Ounces>
    <Size>LARGE</Size>
    <Machinable>TRUE</Machinable>
    <Zone>3</Zone>
    <Postage>
      <MailService>Express Mail to PO Addressee</MailService>
      <Rate>39.20</Rate>
    </Postage>
    <Postage>
      <MailService>Priority Mail</MailService>
      <Rate>8.95</Rate>
    </Postage>
    <Postage>
      <MailService>Parcel Post</MailService>
      <Rate>7.80</Rate>
    </Postage>
    <Postage>
      <MailService>Bound Printed Matter</MailService>
      <Rate>3.53</Rate>
    </Postage>
    <Postage>
      <MailService>Media Mail</MailService>
      <Rate>5.14</Rate>
    </Postage>
    <Postage>
      <MailService>Library Mail</MailService>
      <Rate>4.91</Rate>
    </Postage>
  </Package>
</RateV2Response>

This response document repeats some of the original request information but also includes lots of shipping rate information. In fact, because the request specified All as the shipping method, the response includes shipping rates for all the possible shipping methods. And because the shipping rates are in the XML format, it's not difficult at all to extract a specific rate in PHP code. As an example, the server.php script would return the following piece of data in response to querying for the Priority Mail shipping method:

8.95

Hopefully you're now starting to get the picture for how data is shuttled around in the Shipper application. Just to make sure you didn't get lost in the whirlwind of URLs and XML code, here's a recap of how the process works:

  1. Your client Web page issues an Ajax request to your PHP server script via a URL containing shipping information.

  2. Your PHP server script builds another URL with XML shipping information and issues a request to the USPS Domestic Rates Web service.

  3. The USPS Domestic Rates Web service returns an XML document containing shipping rates for all shipping methods.

  4. Your PHP server script parses out the shipping rate for the desired shipping method and returns it to your client Web page.

  5. The end.

But this isn't truly the end because you haven't even seen the code that makes all this stuff happen. It's obviously time to put everything together.


ch11lev1sec6.html

Putting Together the Shipper Application

Despite what seems like a fairly complex data communication model, the Shipper application is pretty simple in terms of pieces and parts. In fact, only two files go into the application outside of the standard Ajax Toolkit files:

  • HTML Web page (shipper.html)

  • PHP server script (shipper.php)

The next couple sections explore these two pieces of the Shipper application puzzle in more detail.


ch11lev1sec7.html

The Shipper Web Page

The HTML Web page for the Shipper application consists of several text input fields that allow the user to enter shipping information. Most of these fields are decoration to help support the notion of a shopping cart checkout. The ZIP code field obviously does play an important role in the function of the application, as does the shipping method selection box. Figure 11.4 shows the Shipper application in use with an invalid ZIP code so as to reveal the error message display area to the right of the ZIP code input control.

Figure 11.4. The Shipper Web page consists of several input controls and display areas, although the ZIP code input and shipping charge output fields are by far the most important.

[View full size image]

With the layout of the Shipper application in mind, as revealed in the figure, check out the HTML code for the body of the shipper.html Web page:

Code View:
<body onload="initForm()">
  <div id="ajaxState" style="display:none"></div>
  <br />
  <table width="500px">
    <tr>
      <td class="heading" colspan="3">Shipping Information</td>
    </tr>
    <tr>
      <td class="label">Name:</td>
      <td class="value" colspan="2"><input type="text"
        id="name" size="30" /></td>
    </tr>
    <tr>
      <td class="label">Address 1:</td>
      <td class="value" colspan="2"><input type="text"
        id="addr1" size="30" /></td>
    </tr>
    <tr>
      <td class="label">Address 2:</td>
      <td class="value" colspan="2"><input type="text"
        id="addr2" size="30" /></td>
    </tr>
    <tr>
      <td class="label">City:</td>
      <td class="value" colspan="2"><input type="text"
        id="city" size="20" /></td>
    </tr>
    <tr>
      <td class="label">State/Province/Region:</td>
      <td class="value" colspan="2"><input type="text"
        id="state" size="3" /></td>
    </tr>
    <tr>
      <td class="label">ZIP/Postal Code:</td>
      <td class="value"><input type="text" id="zipCode" size="10"
        onchange="getShipRate()" /></td>
      <td class="label" width="50%"><span id="zipCodeErr"
        style="font-size:80%; color:#BB0000;"></span></td>
    </tr>
    <tr>
      <td class="label">Country:</td>
      <td class="value" colspan="2"><input type="text"
         id="country" size="25" value="USA"
         readonly="readonly" /></td>
    </tr>
    <tr>
      <td class="label">Phone Number:</td>
      <td class="value" colspan="2"><input type="text" id="phone"
        size="10" /></td>
    </tr>
  </table>
  <br />
  <table width="500px">
    <tr>
      <td colspan="3" class="heading">Order Summary</td>
   </tr>
   <tr>
      <td class="label">Item:</td>
      <td class="label"><span id="item"></span></td>
      <td class="label"><span id="price"></span></td>
   </tr>
   <tr>
      <td class="label">Shipping & Handling:</td>
      <td class="label">
        <select id="mailService" onchange="getShipRate()">
          <option value="Parcel Post">Parcel Post</option>
          <option value="Priority Mail" selected="selected">
            Priority Mail</option>
          <option value="Express Mail to PO Addressee">
            Express Mail</option>
        </select>
       </td>
       <td class="label"><span id="shiprate">0.00</span></td>
    </tr>
    <tr>
       <td class="label">Total:</td>
       <td class="label"></td>
       <td class="label"><span id="total"></span></td>
    </tr>
  </table>
  <table width="500px">
    <tr>
       <td class="heading"><input type="button"
         value="Proceed with Checkout" /></td>
    </tr>
   </table>
 </body>

Much of this HTML code is devoted to the labels and text boxes for the various input fields. The only input field of consequence is the ZIP code input control, which calls the getShipRate() function in its onchange event handler. Here's this code again just in case you're having a hard time seeing it in the big listing:

<input type="text" id="zipCode" size="10";
  onchange="getShipRate()" />

Immediately following the ZIP code input element is a span element that is used to display ZIP code error message. You have to skip on down the code a bit before you encounter another item of interest, namely the mail service (shipping method) selection list. This list contains three possible options (Parcel Post, Priority Mail, and Express Mail to PO Addressee) and also calls the getShipRate() function in response to an onchange event. Here's this list broken out by itself:

<select id="mailService" onchange="getShipRate()">
  <option value="Parcel Post">Parcel Post</option>
  <option value="Priority Mail" selected="selected">
    Priority Mail</option>
  <option value="Express Mail to PO Addressee">
    Express Mail</option>
</select>

Following the mail service selection list you'll find a few important span elements used to display the results of the shipping rate request. The span element with an ID of shiprate is used to store the actual shipping rate, whereas the element with an ID of total is used to display the order total as calculated after retrieving the shipping rate.

Finally, the Proceed with Checkout button near the end of the code is just there for decoration to indicate that there is a final step in order to complete the online order.

Going back to the start of the body HTML code for the Shipper Web page, you might have noticed a call to the initForm() function in the body's onload event handler. Here's the code for that function:

function initForm() {
  replaceText(document.getElementById("item"), itemDesc);
  replaceText(document.getElementById("price"), itemPrice);
}

The purpose of this code is to initially set the values of the item description and price on the page when the page is first loaded. Neither of these pieces of information impacts the shipping rate in any direct way, although the price does factor into the calculation of the order total.

The item description and price are hard-coded in the Web page, along with several other shipping-related variables. Following is the code that establishes values for these variables:

var origZip = "10022"; // Origination ZIP code
var itemDesc = "Popcorn Holiday Feast";
var itemPrice = 29.99;
var weightLb = "10";
var weightOz = "5";
var container = "Flat Rate Box";
var size = "Large";

Notice how the shipping-related data is deliberately set to match the USPS test data that was mentioned earlier in the chapter. This is very important for testing purposes because the USPS test server won't accept any other data.

Earlier I mentioned the getShipRate() function, which is called to initiate the Ajax request for obtaining a shipping rate. Following is the code for this function:

function getShipRate() {
  // Display the wait image
  document.getElementById("shiprate").innerHTML =
    "<img src='wait.gif' alt='Looking up shipping rate...' />";

  // Assemble the shipping info request string
  var shipInfo = "userID=YOURUSPSUSERID" +
    "&origZip=" + encodeURIComponent(origZip) +
    encodeURIComponent(
    document.getElementById("zipCode").value) +
    "&weightLb=" + encodeURIComponent(weightLb) +
    "&weightOz=" + encodeURIComponent(weightOz) +
    "&container=" + encodeURIComponent(container) +
    "&size=" + encodeURIComponent(size) +
    "&mailService=" +
    encodeURIComponent(
    document.getElementById("mailService").value);
  ajaxSendRequest("GET", "shipper.php?" + shipInfo,
    handleRequest);
}

The first task in this function is to set the shiprate element so that it displays the "loading" image (wait.gif). With the "loading" image displayed, the function moves on to assembling the shipping information, which comes in the form of a URL that is submitted via a GET request on the shipper.php server script. It is very important that you alter this code to include your own unique user ID in the assignment of the userID parameter. In other words, change YOURUSPSUSERID to the ID that was provided to you when you registered for USPS Web Tools.

The Ajax shipping request is handled by the handleRequest() function, which is responsible for receiving a single shipping rate from the server script and updating the page appropriately. Following is the code for this function:

function handleRequest() {
  ajaxUpdateState();
  if (request.readyState == 4 && request.status == 200) {
    var shipRate = request.responseText;
    if (parseFloat(shipRate) != 0.0) {
      replaceText(document.getElementById("zipCodeErr"), "");
      updateTotal(shipRate);
    }
    else {
      replaceText(document.getElementById("zipCodeErr"),
        "Cannot ship to this ZIP code.");
      updateTotal("0.00");
    }
  }
}

This function is fairly simple for an Ajax request handler, and primarily involves converting the shipping rate into a floating-point number and then calculating the order total with a call to updateTotal(). The error message area of the page is also set so that a message is displayed if the request failed or the message is cleared if the request is successful.

Hang on because we're almost finished with the code for the Shipper Web page. Following is the last code you need to know about, which is the updateTotal() function:

function updateTotal(shipRate) {
  document.getElementById("shiprate").innerHTML = shipRate;
  var total = itemPrice + parseFloat(shipRate);
  replaceText(document.getElementById("total"), "$" + total);
}

The updateTotal() function accepts a new shipping rate as its only parameter, and then updates the page and calculates a new order total based on the rate. One subtlety in this code that may seem confusing at first is the usage of innerHTML versus the replaceText() function. Ideally you would use replaceText() only, because it doesn't alter the structure of the underlying HTML code. However, the fact that the shipping rate span element serves double duty as a rate display and a "loading" image display means that you must use innerHTML instead. This is necessary because switching between text and an image does alter the structure of the HTML code, which isn't possible using the replaceText() function alone.


ch11lev1sec8.html

The Shipper Server Script

With the needs of the client side of the Shipper application in mind, it's time to turn your attention to the server. You've already learned that the role of the shipper.php script is to use shipping information that has been passed to it to assemble an XML document for submission to the USPS Domestic Rates Web service. It then must take the resulting response XML document and extract a specific shipping rate from it.

Although this sounds like it may take a lot of messy code, the PHP server script for the Shipper application actually isn't very complex, as the following code reveals:

// Generate an XML document for the USPS server request
$uspsRequest =
  "http://testing.shippingapis.com/ShippingAPITest.dll?";
$uspsRequest .= "API=RateV2&XML=";
$uspsRequest .= "<RateV2Request%20USERID=\"";
$uspsRequest .= $_REQUEST["userID"];
$uspsRequest .= "\"%20PASSWORD=\"";
$uspsRequest .= $_REQUEST["password"] . "\">";
$uspsRequest .= "<Package%20ID=\"0\"><Service>" . "All";
$uspsRequest .= "</Service>";
$uspsRequest .= "<ZipOrigination>" . $_REQUEST["origZip"];
$uspsRequest .= "</ZipOrigination>";
$uspsRequest .= "<ZipDestination>" . $_REQUEST["destZip"];
$uspsRequest .= "</ZipDestination>";
$uspsRequest .= "<Pounds>" . $_REQUEST["weightLb"] . "</Pounds>";
$uspsRequest .= "<Ounces>" . $_REQUEST["weightOz"] . "</Ounces>";
$uspsRequest .= "<Container>" . urlencode($_REQUEST["container"]);
$uspsRequest .= "</Container>";
$uspsRequest .= "<Size>" . $_REQUEST["size"] . "</Size>";
$uspsRequest .= "<Machinable>" . "true" . "</Machinable>";
$uspsRequest .= "</Package></RateV2Request>";

This code isn't the entire PHP script, but it is the biggest chunk of code, responsible for assembling an XML document from the shipping information passed into the script as PHP parameters.

With the USPS request XML document ready to roll, the script goes ahead and issues the request, receiving a response XML document in return:

// Parse the shipping response data into a structure
$rawShipping = file_get_contents($uspsRequest);
$xml = new SimpleXmlElement($rawShipping);

You now have the XML response data stored in the $xml PHP variable and are ready to parse out the specific shipping rate that matches the shipping method passed along in the mailService parameter:

// Return the rate for the appropriate mail service
$rate = 0;
if ($xml->Package->Postage != null) {
  foreach ($xml->Package->Postage as $postage) {
    if ($postage->MailService == $_REQUEST['mailService']) {
      $rate = $postage->Rate;
      break;
    }
  }
}
echo $rate;

This code steps through the response XML document looking for <Postage> tags. Within each <Postage> tag found, the contents of the child <MailService> tag is checked against the specified mail service, such as Priority Mail. If a match is found, the contents of the <Rate> tag are returned from the script for the client to process.

Although I'm sure you're itching to get a break from all this code and test out the Shipper application, let's take a second to test the PHP script by itself before moving on. You saw how this is done in earlier chapters by opening PHP scripts directly in a browser—here's a sample URL for testing the Shipper script:

http://www.yourdomain.com/shipper.php?userID=YOURUSPSUSERID&
origZip=10022&destZip=20008&weightLb=10&weightOz=5&container=
Flat%20Rate%20Box&size=Large&mailService=Priority%20Mail

Assuming the shipper.php file is stored on your server, change the domain to match yours in this line of code, replace YOURUSPSUSERID with your user ID, and then enter the URL into your Web browser. Or use the following URL directly on the live CD accompanying the book, still making sure to replace YOURUSPSUSERID with your own user ID:

http://localhost/chap11/shipper/shipper.php?
userID=YOURUSPSUSERID&origZip=10022&destZip=20008&weightLb=10&
weightOz=5&container=Flat%20Rate%20Box&size=Large&mailService=
Priority%20Mail

Figure 11.5 shows the shipping rate generated by the PHP script.

Figure 11.5. The only piece of information returned by the Shipper PHP script is a single shipping charge.

[View full size image]

Although it would be interesting to experiment with different shipping information in the URL, such as different origin and destination ZIP codes, the USPS test server only supports the test data you see here. You'll have to get validation with the USPS and move over to its production server in order to do more thorough testing. You find out how to obtain validation later in the chapter in the section "Giving Shipper an Extreme Ajax Makeover."


ch11lev1sec9.html

Testing Shipper

Before attempting to test the Shipper application, make sure to register for your own USPS Web Tools user ID at http://www.usps.com/webtools/. You will then need to plug this user ID into the HTML code in the shipper.html Web page as explained in the previous section. Keep in mind that Shipper will not work unless you register for and insert your own user ID into the HTML code for the application.

With that bit of housekeeping out of the way, take a look at Figure 11.6, which shows the Shipper application open and ready to do some serious shipping rate calculating.

Figure 11.6. The Shipper application starts out with the entire user interface blank except for the default Country field, which cannot be changed from USA.

[View full size image]

The user interface starts out blank, so feel free to enter information as if you're finalizing the checkout of an online purchase. Or save yourself some time and jump straight to the ZIP code field on the page. First try entering a ZIP code that doesn't even exist in the real world (yet), such as 20080. Figure 11.7 shows how the application displays an error/helper message to indicate that shipping rate information for the ZIP code doesn't exist.

Figure 11.7. Entering an invalid ZIP code results in an error/helper message beside the ZIP code field.

[View full size image]

In reality, any ZIP code you enter other than 20008 (Washington, DC) is considered invalid for testing purposes, so you can enter just about anything and get the error message. To see a successful shipping rate calculation, enter 20008 as the ZIP code and navigate off the ZIP code field. Figure 11.8 shows the dynamically retrieved shipping charge and the newly calculated order total.

Figure 11.8. Entering a valid ZIP code results in a successful Ajax request of the shipping rate, which also results in the calculation of the order total.

[View full size image]

Unless you were paying careful attention, you might have missed the "loading" image that appeared in place of the shipping charge while the request was taking place. Try again by selecting a different shipping method and watching the shipping rate closely. Figure 11.9 shows the "loading" image in action.

Figure 11.9. The small "loading" image appears in place of the shipping charge while an Ajax request is being carried out.

[View full size image]

This figure shows how the "loading" image provides a subtle but effective indication that something is taking place in the background related to the shipping rate. When the new rate is obtained, the image disappears and the new rate is displayed (see Figure 11.10).

Figure 11.10. Changing shipping methods also results in a request, and therefore a new shipping rate and order total.

[View full size image]

Although I'd like to tell you to experiment with all kinds of different ZIP codes to see how the application responds to shipping an item all over the country, this isn't an option with the USPS test server. You'll need to take an additional step to enable the application so that it can access the full range of shipping rates. The next section tells you what to do.


ch11lev1sec10.html

Giving Shipper an Extreme Ajax Makeover

Because the Shipper application bases its shipping options on U.S. Postal Service shipping methods, it is highly dependent upon the U.S. Postal Service Domestic Rates calculator Web service, which is part of the USPS Web Tools (http://www.usps.com/webtools/). Unlike many of the other third-party Web services used throughout the book, the USPS Web Tools are tightly controlled and can only be used by carefully coordinating your development efforts with the USPS.

More specifically, you must go through a validation process in order to move beyond the limited test data on the USPS test server and try out your application on the USPS production server. This validation is carried out by the USPS Internet Customer Care Center (ICCC), which is available at icustomercare@usps.com or 1-800-344-7779 (7:00 a.m. to 11:00 p.m. EST). You must already be a registered USPS Web Tools user (with an ID) and have tested the application using the Domestic Rates Web Tool server before contacting the ICCC for access to the production server. The first part of the Shipper extreme makeover, therefore, is simply to gain access to the USPS production server so that you can try out a full range of test ZIP codes.

Note

You will have to contact the ICCC in order to use the Shipper application in any real capacity because it is limited to using only USPS-specified test data when running on the USPS test server.

After you've been validated by the ICCC and obtained the URL of the Domestic Rates Web Tool production server, be sure to change the Shipper application to use the production server by changing the following line of code near the beginning of the shipper.php file:

$uspsRequest =
  "http://testing.shippingapis.com/ShippingAPITest.dll?
  API=RateV2&";

The first part of the URL in this code, http://testing.shippingapis.com/Shipping-APITest.dll, is the URL of the USPS test server and is the part of the code you'll need to change to the production URL. This should be the only change required to move the Shipper application from the USPS test server to the production server, and thus open you up to trying out any ZIP codes to calculate shipping charges.

Once you get the Shipper application successfully running on the USPS production server, you'll want to seriously consider incorporating the Ajax code into your own Web pages. Unfortunately, this facet of the extreme makeover is entirely dependent upon your specific site design, so it's hard to give specifics about how to carry out the design and implementation. What I can do, however, is provide a general strategy for incorporating the Ajax shipping calculator into an existing shopping cart.

First off, you'll need to import the two relevant Ajax Toolkit files, like this:

<script type="text/javascript" src="ajaxkit.js"> </script>
<script type="text/javascript" src="domkit.js"> </script>

You then need to make sure you have an input text element for the ZIP code input field, as well as a span element for the ZIP code error message. If you already have a ZIP code input element, make sure to add an onchange event handler similar to the one in the Shipper application. Here's the relevant code from the Shipper Web page:

<td class="value"><input type="text" id="zipCode" size="10"
  onchange="getShipRate()" /></td>
<td class="label" width="50%"><span id="zipCodeErr"
  style="font-size:80%; color:#BB0000;"></span></td>

Notice that the ZIP code input element calls the getShipRate() function to dynamically grab the shipping charge from the USPS server. You saw this function earlier, so I won't repeat it here. However, you'll need to copy and paste its code into the head of your page, along with the response handler function, handleRequest().

You may already have a select element for choosing the shipping method, but if you don't you'll need to add that to your page. Following is the selection list used in the Shipper application to offer a choice of USPS shipping methods:

<select id="mailService" onchange="getShipRate()">
  <option value="Parcel Post">Parcel Post</option>
  <option value="Priority Mail" selected="selected">
    Priority Mail</option>
  <option value="Express Mail to PO Addressee">
    Express Mail</option>
</select>

It is extremely important to notice how the value of each option is set to exactly match the shipping method as specified in the Domestic Rates documentation for the USPS Web Tools. This is important because the Shipper application uses this value as the basis of the rate request, which means it must exactly match a shipping method in order for the lookup to work. In other words, value="US Priority Mail" won't work because the shipping method is "Priority Mail", not "US Priority Mail".

Note

It is possible to support other USPS shipping methods beyond the three shown in the Shipper application. To find out about all of the available shipping methods, take a look at the USPS Web Tools documentation at http://www.usps.com/webtools/technical.htm. If you'd like to support a different shipping provider such as FedEx or UPS, you'll need to dig into its documentation and do some work to support its request/response formats.

Finally, there are several "shopping cart" variables in the Shipper application that you'll need to provide or wire to your existing shopping cart fields:

var origZip = "10022"; // Origination ZIP code
var itemDesc = "Popcorn Holiday Feast";
var itemPrice = 29.99;
var weightLb = "10";
var weightOz = "5";
var container = "Flat Rate Box";
var size = "Large";

Keep in mind that most of these variables will be somehow tied to real data that has either already been entered or selected in your shopping cart. I opted to make them static in the Shipper application just to keep things simple; my goal was showing how to calculate a shipping charge with Ajax, not how to build an entire shopping cart.

If you follow these general design guidelines, you should be able to tie the Ajax dynamic shipping charge lookup into your own Web site without too much trouble.


ch11lev1sec11.html

Summary

This chapter explored the dynamic lookup of shipping charges, which falls clearly within the realm of a problem needing an Ajax solution. It simply shouldn't be necessary to navigate from one page to the next in a shopping cart just to find out shipping charges for an online purchase. Not only that, but all you really need to provide in order to determine the charges is your ZIP code. The Shipper application in this chapter demonstrated how the clever use of Ajax can make a subtle but substantial improvement to a shopping cart or any other application that needs to calculate a shipping charge on the fly and present it to the user.


ch12.html

Chapter 12. Adding an Ajax-Powered Rating System to Your Site

Ajax Yet Again in Cartoons

MGM's Ajax Corporation isn't the only time Ajax has been used in cartoons. Duckman was a regular show on the USA Network in the mid 1990s, and featured a character named Ajax Duckman, who was the son of the title character, Eric Duckman. Ajax Duckman was voiced by musician Dweezil Zappa, and was somewhat of a slacker teenager on the show.

An increasingly popular component of many popular Web sites is the ability to rate things. Amazon probably started the trend when it provided the ability to rate products and write your own reviews. Since then, all kinds of different Web sites offer a rating system of some sort, be it for rating movies, music, photographs, blog posts, whatever. If it can be posted online, it can be rated. I suppose deep down most of us are critics at heart, so the idea of being able to rate anything and everything somehow taps into that need to share our criticism and in many cases our praise. Admittedly, it probably isn't fair to simplify everything in the world to a five-star rating, but it can give you a quick glimpse at how people perceive something.

This chapter is without a doubt the most ambitious chapter in the book in terms of how it utilizes Ajax to add five-star ratings to any content on a Web page. By ambitious, I simply mean that the Rater sample application is considerably more advanced in its usage of Ajax when you consider that it has to be able to read and write multiple ratings to a file or database on the server while preventing duplicate votes by the same user. The good news is that the vast majority of this complexity is hidden within the Ajax Toolkit, meaning that your job primarily boils down to properly using the Toolkit, as opposed to constructing your own rating code.

The following files are used by the Rater application in this chapter, and are located on the live Linux CD-ROM with the book in the chap12 example code folder:

  • rater.html—Rater main Web page

  • cookiereset.html—Cookie reset Web page for simulating unique users

  • ajaxkit.js— Core Ajax functions for the Ajax Toolkit

  • domkit.js—DOM-related functions for the Ajax Toolkit

  • ratingkit.js—Rating-related functions for the Ajax Toolkit

  • ratingkit.php—Server script for saving and loading ratings

  • ratingkit.css—Style sheet for five-star ratings

  • star.gif—Star images used to represent a five-star rating

  • star_sm.gif—Smaller star images used to represent a smaller five-star rating

The Challenge: Adding Ratings to a Web Site

A handy way of determining the importance of an item is to consider whether it would make the cut if you were to be stranded on a deserted island and could only bring a selected number of items. For example, what if you could only take a single music CD to listen to for the many years you might be stranded with no companionship (but hopefully plenty of batteries to power your CD player!)? What CD would you choose?

Hopefully you never end up having to actually make the deserted island CD selection. Short of that, you might find it useful to rate your favorite CDs on Amazon.com so that other people can make more educated music buying decisions. Amazon.com allows you to rate music CDs and pretty much everything else it has for sale using a five-star rating system. If you're near a computer right now, take a moment to visit Amazon.com and view a music CD. This will clue you in as to how an online rating system works.

If you look at the five stars below the name of the artist and CD title, you'll notice that out beside the stars is a count of how many customers issued ratings. This is very important because it gives you an idea as to how accurate the rating might be—if only a handful of people have rated the item, the rating might not mean so much.

The real reason for mentioning this rating example is to point out how the Amazon.com rating approach involves a fairly unimpressive user interface for choosing the rating. I'm referring to the selection list used to select a rating, which allows you to choose a text description of the star rating, such as "five stars" or "four stars." Aside from the fact that Amazon.com also supports a text review to go with the rating, you must also preview and accept your rating before it goes into effect. It would be much more intuitive and efficient if you could just click directly on the five-star rating to rate the item right there on the main item page. Granted, this wouldn't address the need for writing a review, but not everyone is interested in writing a review—sometimes a quick "hit-and-run" rating is all you need.

The challenge for this chapter is to use Ajax to incorporate an interactive five-star rating component into a Web page so that users can vote on items without leaving the page. This is in keeping with much of what you've already learned about Ajax in terms of minimizing page reloads when all you're doing is tweaking a small amount of data. In this case, all you want to do is submit a single piece of rating data to the server and then see the total rating tally after the vote is processed. This is definitely within the realm of something Ajax can handle.

One thorny part of this challenge that you may already be curious about is the persistent storage of the rating votes. If you think back on all the sample Ajax applications you've seen thus far, this is the first one that has to remember something the user submits. More specifically, the Rater application must somehow store on the server each vote for each item after it is issued. Fortunately, I provide you with a prebuilt rating component that handles all the details of storing rating data on the server in an XML document. I also provide you with some ideas about possibly using a database instead of an XML file if you're so inclined.

This rating component I'm talking about is included as part of the Ajax Toolkit included on the CD-ROM with this book. The component involves both client- and server-side code, as well as a few images and a style sheet. Behind the scenes, an Ajax-powered five-star rating system is a bit trickier than you might imagine, which is why so many files are necessary in order to work the magic.

Within the client-side JavaScript code for the rating component (contained in ratingkit.js), the following two functions are used to control the rating system:

  • initRatings()—Initializes the ratings for all of the items on a page

  • setRating()—Issues a rating vote for a single item

With a little help from the PHP server script (ratingkit.php), these functions make it possible to assign a rating to as many individual items on a page as you want. Not only that, but the rating component is smart enough to limit the number of votes on a given computer to a single vote per user. It does this through the clever use of cookies, which provide a perfect mechanism for remembering whether or not the user has taken a certain action (such as rating a particular item).

Hopefully I've sold you on the fact that I've already done the lion's share of the ratings work by handing you a prebuilt component. What does that leave for the Rater application challenge? The challenge for the Rater application is to properly set up the HTML code for ratable items so that they tie into the rating component and issue their votes correctly. Also, several CSS rating classes are part of the rating component and must be carefully assigned to elements on the Rater page in order for the rating to work.

To keep the HTML code for the Rater application fairly simple and not involve a bunch of extra images or other resources, the items being rated are famous quotations. The Rater Web page consists of five famous quotations, and therefore five different ratings—one per quotation. The Rater Web page needs to include a unique rating component for each quotation and properly identify it so that votes on that quotation are stored on the server for future retrieval. When all is said and done, the Rater application will allow countless people all over the Web to vote on their favorite quotations, with all the rating votes tallied on the server and the total number of votes displayed on the page.

What you'll take with you after developing the Rater application is the ability to reuse the rating component to rate any kind of Web content.


ch12lev1sec1.html

Chapter 12. Adding an Ajax-Powered Rating System to Your Site

Ajax Yet Again in Cartoons

MGM's Ajax Corporation isn't the only time Ajax has been used in cartoons. Duckman was a regular show on the USA Network in the mid 1990s, and featured a character named Ajax Duckman, who was the son of the title character, Eric Duckman. Ajax Duckman was voiced by musician Dweezil Zappa, and was somewhat of a slacker teenager on the show.

An increasingly popular component of many popular Web sites is the ability to rate things. Amazon probably started the trend when it provided the ability to rate products and write your own reviews. Since then, all kinds of different Web sites offer a rating system of some sort, be it for rating movies, music, photographs, blog posts, whatever. If it can be posted online, it can be rated. I suppose deep down most of us are critics at heart, so the idea of being able to rate anything and everything somehow taps into that need to share our criticism and in many cases our praise. Admittedly, it probably isn't fair to simplify everything in the world to a five-star rating, but it can give you a quick glimpse at how people perceive something.

This chapter is without a doubt the most ambitious chapter in the book in terms of how it utilizes Ajax to add five-star ratings to any content on a Web page. By ambitious, I simply mean that the Rater sample application is considerably more advanced in its usage of Ajax when you consider that it has to be able to read and write multiple ratings to a file or database on the server while preventing duplicate votes by the same user. The good news is that the vast majority of this complexity is hidden within the Ajax Toolkit, meaning that your job primarily boils down to properly using the Toolkit, as opposed to constructing your own rating code.

The following files are used by the Rater application in this chapter, and are located on the live Linux CD-ROM with the book in the chap12 example code folder:

  • rater.html—Rater main Web page

  • cookiereset.html—Cookie reset Web page for simulating unique users

  • ajaxkit.js— Core Ajax functions for the Ajax Toolkit

  • domkit.js—DOM-related functions for the Ajax Toolkit

  • ratingkit.js—Rating-related functions for the Ajax Toolkit

  • ratingkit.php—Server script for saving and loading ratings

  • ratingkit.css—Style sheet for five-star ratings

  • star.gif—Star images used to represent a five-star rating

  • star_sm.gif—Smaller star images used to represent a smaller five-star rating

The Challenge: Adding Ratings to a Web Site

A handy way of determining the importance of an item is to consider whether it would make the cut if you were to be stranded on a deserted island and could only bring a selected number of items. For example, what if you could only take a single music CD to listen to for the many years you might be stranded with no companionship (but hopefully plenty of batteries to power your CD player!)? What CD would you choose?

Hopefully you never end up having to actually make the deserted island CD selection. Short of that, you might find it useful to rate your favorite CDs on Amazon.com so that other people can make more educated music buying decisions. Amazon.com allows you to rate music CDs and pretty much everything else it has for sale using a five-star rating system. If you're near a computer right now, take a moment to visit Amazon.com and view a music CD. This will clue you in as to how an online rating system works.

If you look at the five stars below the name of the artist and CD title, you'll notice that out beside the stars is a count of how many customers issued ratings. This is very important because it gives you an idea as to how accurate the rating might be—if only a handful of people have rated the item, the rating might not mean so much.

The real reason for mentioning this rating example is to point out how the Amazon.com rating approach involves a fairly unimpressive user interface for choosing the rating. I'm referring to the selection list used to select a rating, which allows you to choose a text description of the star rating, such as "five stars" or "four stars." Aside from the fact that Amazon.com also supports a text review to go with the rating, you must also preview and accept your rating before it goes into effect. It would be much more intuitive and efficient if you could just click directly on the five-star rating to rate the item right there on the main item page. Granted, this wouldn't address the need for writing a review, but not everyone is interested in writing a review—sometimes a quick "hit-and-run" rating is all you need.

The challenge for this chapter is to use Ajax to incorporate an interactive five-star rating component into a Web page so that users can vote on items without leaving the page. This is in keeping with much of what you've already learned about Ajax in terms of minimizing page reloads when all you're doing is tweaking a small amount of data. In this case, all you want to do is submit a single piece of rating data to the server and then see the total rating tally after the vote is processed. This is definitely within the realm of something Ajax can handle.

One thorny part of this challenge that you may already be curious about is the persistent storage of the rating votes. If you think back on all the sample Ajax applications you've seen thus far, this is the first one that has to remember something the user submits. More specifically, the Rater application must somehow store on the server each vote for each item after it is issued. Fortunately, I provide you with a prebuilt rating component that handles all the details of storing rating data on the server in an XML document. I also provide you with some ideas about possibly using a database instead of an XML file if you're so inclined.

This rating component I'm talking about is included as part of the Ajax Toolkit included on the CD-ROM with this book. The component involves both client- and server-side code, as well as a few images and a style sheet. Behind the scenes, an Ajax-powered five-star rating system is a bit trickier than you might imagine, which is why so many files are necessary in order to work the magic.

Within the client-side JavaScript code for the rating component (contained in ratingkit.js), the following two functions are used to control the rating system:

  • initRatings()—Initializes the ratings for all of the items on a page

  • setRating()—Issues a rating vote for a single item

With a little help from the PHP server script (ratingkit.php), these functions make it possible to assign a rating to as many individual items on a page as you want. Not only that, but the rating component is smart enough to limit the number of votes on a given computer to a single vote per user. It does this through the clever use of cookies, which provide a perfect mechanism for remembering whether or not the user has taken a certain action (such as rating a particular item).

Hopefully I've sold you on the fact that I've already done the lion's share of the ratings work by handing you a prebuilt component. What does that leave for the Rater application challenge? The challenge for the Rater application is to properly set up the HTML code for ratable items so that they tie into the rating component and issue their votes correctly. Also, several CSS rating classes are part of the rating component and must be carefully assigned to elements on the Rater page in order for the rating to work.

To keep the HTML code for the Rater application fairly simple and not involve a bunch of extra images or other resources, the items being rated are famous quotations. The Rater Web page consists of five famous quotations, and therefore five different ratings—one per quotation. The Rater Web page needs to include a unique rating component for each quotation and properly identify it so that votes on that quotation are stored on the server for future retrieval. When all is said and done, the Rater application will allow countless people all over the Web to vote on their favorite quotations, with all the rating votes tallied on the server and the total number of votes displayed on the page.

What you'll take with you after developing the Rater application is the ability to reuse the rating component to rate any kind of Web content.


ch12lev1sec2.html

The Design: Designing a Rater Application

The design of the Rater application begins with the quotations themselves because they are driving the rating process in this particular example. Because the quotations are just text, it is sufficient to wrap them up in div elements without any special formatting or other code. Although a rating appears immediately below a quotation, there is nothing directly tying a rating and a quotation together in terms of HTML code.

The connection between a rating and a quotation has everything to do with the "item ID" of the rating, which is a piece of text used to uniquely identify a rating among other ratings. If you think of all the ratings on your Web site as one big collection, which they are, then each of them has a unique ID that allows you to tell them apart. The item ID should somehow give you a clue as to what quotation the rating is connected to. For example, you could use the last name of the quotation author as the ID for a rating, which is in fact what the Rater application uses.

The item ID is critical because it gets stored along with the rating votes, and is therefore what is used to associate a stored rating with a quotation on the page. Speaking of quotations on the page, Figure 12.1 shows the basic layout of the Rater user interface, including the quotations and their respective ratings.

Figure 12.1. The user interface for the Rater application consists of several text quotations with a rating component for each.

The figure reveals how each quotation is immediately followed by a rating and its associated helper text. The helper text initially just instructs you to click the rating in order to submit a vote. Once you've voted on a rating, the helper text changes to show you how many votes have been cast for the rating. So the helper text serves double duty—first as an instruction and then as a means of displaying rating information.

The rating component provided in the Ajax Toolkit handles all the details of the Ajax requests in the Rater application. The goal in this chapter is not to dissect the inner workings of the rater component but instead to show you how to use it to incorporate ratings into Web pages. Even so, it's worth taking a quick peek at how Ajax is at work in the component in the form of client requests and server responses.

The Client Request

Two different client requests are involved with the rating component: one for initially obtaining rating information for all of the ratings on a page, and another for casting a vote for a particular rating. The first request occurs exactly one time when a page is initially loaded, whereas the second request can occur multiple times if you have multiple ratings on a page. Of course, the rating component does use cookies to prevent you from casting more than one vote on a given rating. But the fact remains that each vote on each rating results in an Ajax request.

When an Ajax request is made for all of the ratings, the client isn't required to pass along any information. In other words, the URL for the Ajax request consists of nothing more than the PHP server script that reads the ratings from an XML file and returns the results.

Unlike the rating retrieval request, the Ajax request for casting a rating vote does require parameters. The parameters required of this request are the item ID and the rating itself (one to five stars). These two parameters are passed along to the server where they are properly integrated into the rating data, meaning that they are used to increment the number of votes and recalculate the average rating.

The Server Response

The server responses for the rating component in the Ajax Toolkit vary considerably depending on the request. When retrieving all of the ratings for the purposes of initializing the ratings on a page, the server returns all of the ratings that have been stored as an XML document. It is then up to the code on the client to determine which ratings apply to the page, based upon the rating IDs.

The server response for the setting of a rating involves the newly calculated rating average and the total number of votes that have been cast for the specified item ID. These two pieces of information are returned to the client script, which then updates the rating on the page appropriately.

Making Sense of the Client-to-Server Conversation

To help get a feel for the flow of data that takes place between the client and server in the Rater application (rater component), take a look at Figure 12.2.

Figure 12.2. Behind the scenes in the Rater application are two Ajax requests for initializing the ratings and submitting new rating votes.

The figure reveals how the initial rating request involves no flow of data from the client but returns a full-blown XML document containing all of the ratings. Because no parameters are required when the Ajax request is submitted, the URL for the request is simply the name of the PHP server script:

ratingkit.php

Although the data flowing from the client to the server is quite minimal, the data returned in the other direction is much more interesting. Following is an example of what the response XML document looks like:

Code View:
<?xml version="1.0" encoding="utf-8"?>
<ratings>
  <rating>
    <id>twain</id>
    <avg>4.5</avg>
    <votes>2</votes>
  </rating>
  <rating>
    <id>ali</id>
    <avg>3.33333333333</avg>
    <votes>3</votes>
  </rating>
  <rating>
    <id>einstein</id>
    <avg>3</avg>
    <votes>2</votes>
  </rating>
  <rating>
    <id>shaw</id>
    <avg>4</avg>
    <votes>2</votes>
  </rating>
  <rating>
    <id>paine</id>
    <avg>4</avg>
    <votes>1</votes>
  </rating>
 </ratings>

The structure of this XML document is pretty simple in that it consists of a list of ratings, each of which has three distinct pieces of data:

  • Item ID (<id>)

  • Rating average (<avg>)

  • Number of votes (<votes>)

This information is sufficient to describe a rating for a single item. Each <rating> tag in the XML document corresponds to a rating for a single item. The document as a whole serves as the data format for the ratings, meaning that if you open the ratings.xml file generated on the server, you'll see the same XML code. It is important to note that this file serves as the main database for all ratings on your site, potentially across multiple pages. The key is the item ID, which allows you to use ratings anywhere you want on your site as long as they are properly ID'd.

Note

As you find out later in the chapter in the "Giving Rater an Extreme Ajax Makeover" section, item IDs can be any text you want. Although the Rater application uses names as IDs, you can just as easily use numbers or a combination of letters and numbers. The important thing is to use item IDs that are unique and easy to associate with an item. For example, an item ID for a rating of a book might use the book's International Standard Book Number (ISBN) so that the ID is guaranteed unique and also has an obvious association with the book.

If you ever want to view the XML data stored for the ratings on your site, just enter the rating component's PHP server script (ratingkit.php) in your browser with no parameters or anything. Figure 12.3 shows the rating XML code as it appears in a browser by directly opening the server script.

Figure 12.3. Directly entering the URL of the PHP server script for the rating component results in the display of the rating XML document.

[View full size image]

The other Ajax request used in the Rater application involves storing a new rating. The underlying code in the server script used to process this request is a bit messier because it has to be smart enough to create a new XML file (ratings.xml) if it doesn't already exist (i.e., this is the very first vote on any item). Assuming the XML file does in fact exist, the server script has to search through the XML code and find the rating based upon the item ID. It then has to update the rating by calculating a new average and incrementing the number of votes.

The URL used to issue a new rating involves passing along the item ID and rating as parameters to the server script. However, unlike other Ajax requests you've seen throughout the book, this request is issued as a POST instead of a GET because the intent of the request is to alter information on the server. In a POST request, the URL is simply the name of the server script, while the parameters (item ID and rating) are passed as a separate parameter to the ajaxSendRequest() function in the Ajax Toolkit in the file ajaxkit.js. I realize I'm drifting into some details that you may not be all that interested in knowing, given that the focus here is code reuse, but I want you to understand enough about the inner workings of the rater component to potentially be able to modify it if need be.

Getting back to the rating submission request, the response from the server includes a newly calculated rating average and the total number of votes that have been cast. Although XML could certainly be used to format this return data, it just isn't necessary. So the data is returned as a colon-delimited pair, like this:

4.5:2

This is the data returned after issuing the last vote made on the first quote in the XML data you just saw. If you look back at that data, you'll see the following code:

<rating>
  <id>twain</id>
  <avg>4.5</avg>
  <votes>2</votes>
</rating>

So, the server response to a rating vote that has been cast is just a matter of returning a couple pieces of data that have just been written to the XML file: the <avg> and <votes> content.


ch12lev1sec3.html

Putting Together the Rater Application

In addition to several files that are part of the Ajax Toolkit included on the CD-ROM accompanying the book, the Rater application consists of a single Web page and a helper Web page that isn't strictly required:

  • HTML Web page (rater.html)

  • Cookie Reset Web page (cookiereset.html)

The Rater application is contained within the Rater Web page (rater.html), whereas the Cookie Reset Web page (cookiereset.html) is a separate helper page for clearing the rating cookies for testing purposes. The next couple sections examine these files in more detail.

The Rater Web Page

The Rater Web page makes use of five individual ratings that are each applied to a text quotation that appears on the page just before each rating. The idea is that you are able to read a quotation and then immediately rate it. Figure 12.4 shows the Rater Web page with several rating votes already made but a few items remaining in an unrated state.

Figure 12.4. The Rater Web page displays several quotations along with a five-star rating component for each one.

[View full size image]

If you pay close attention to the figure, you'll see that the rating for the Muhammad Ali quotation appears with larger stars and text. This demonstrates how the rating component supports two different sizes. In practical terms, the difference between the small and large versions of the rating component simply involves the usage of the different CSS style classes for the ratings.

The actual code for the Rater Web page is admittedly on the long side, so brace yourself. Just keep in mind that the main reason for the long code listing is because the page is using five different ratings, each of which requires several lines of code. Here's abbreviated code for the body of the Rater page, which is where all of the interesting stuff takes place:

Code View:
<body onload="initRatings()">
  <div id="ajaxState" style="display:none"></div>
  <br />
  <div>A banker is a fellow who lends you his umbrella when the
    sun is shining, but wants it back the minute it begins to
    rain.<br />
    - Mark Twain</div>
  <div>
    <span class="rating-label-small">Rating:</span>
    <span class="inline-rating">
      <ul class="star-rating small-star">
        <li id="twain-rating" class="current-rating"
style="width:0%">Rating</li>
        <li><a href="javascript:setRating('twain', 1);"
          class="one-star">1</a></li>
        <li><a href="javascript:setRating('twain', 2);"
          class="two-stars">2</a></li>
        <li><a href="javascript:setRating('twain', 3);"
          class="three-stars">3</a></li>
        <li><a href="javascript:setRating('twain', 4);"
          class="four-stars">4</a></li>
        <li><a href="javascript:setRating('twain', 5);"
          class="five-stars">5</a></li>
     </ul>
   </span>
   <span id="twain-info" class="rating-info-small">
     (click to vote)</span>
  </div>
  <hr />
  <div>Learn from yesterday, live for today, hope for tomorrow.
   The important thing is not to stop questioning.<br />
   - Albert Einstein</div>
  <div>
    <span class="rating-label-small">Rating:</span>
    <span class="inline-rating">
      <ul class="star-rating small-star">
        <li id="einstein-rating" class="current-rating"
          style="width:0%">Rating</li>
        <li><a href="javascript:setRating('einstein', 1);"
          class="one-star">1</a></li>
        <li><a href="javascript:setRating('einstein', 2);"
          class="two-stars">2</a></li>
        <li><a href="javascript:setRating('einstein', 3);"
          class="three-stars">3</a></li>
        <li><a href="javascript:setRating('einstein', 4);"
          class="four-stars">4</a></li>
        <li><a href="javascript:setRating('einstein', 5);"
          class="five-stars">5</a></li>
      </ul>
    </span>
    <span id="einstein-info" class="rating-info-small">
      (click to vote)</span>
  </div>
  ...
</body>

The key to this code is the careful usage of CSS style classes for the ratings. These classes are defined in the ratingkit.css style sheet and are responsible for the animated hover effect when you drag the mouse over the rating stars. This CSS approach to implementing a five-star rating was originally created by Rogie King of Komodo Media, which is located on the Web at http://www.komodomedia.com/. The code works so well that I used it as the basis for the rating component in the Ajax Toolkit.

Each rating in the Rater Web page is created as an unordered list where each star in the rating is an item in the list. The twist is that the list items are displayed horizontally instead of vertically, which is what causes the stars to appear horizontally. This may seem like a strange way to use a list, and it is, but it ends up working quite well for ratings. The trick is then to apply the appropriate styles to the list so that the hover effect works as intended.

The first step is to create a span element that houses the label for the rating, which is just static text:

<span class="rating-label-small">Rating:</span>

Of course, even the static text must have the appropriate CSS style class applied to it (rating-label-small). If you want a larger label for the larger-sized rating component, use rating-label instead of rating-label-small.

The next step is to create another span element that serves as the outer shell for the rating component:

<span class="inline-rating">

Within this span element you then add the unordered list container element, ul, like this:

<ul class="star-rating small-star">

This ul element is styled for a small rating component, meaning that it will use the smaller star images found in the star_sm.gif image file. If you want to use the larger rating component instead, just leave off the small-star class so that the code looks like this:

<ul class="star-rating">

Up to now the rating component is entirely generic with no code that is specific to an item. That's about to change with the addition of the first list item, which is a special item that controls how many of the stars are visible:

    <li id="twain-rating" class="current-rating"
style="width:0%">Rating</li>

Now you see the first evidence of an item-specific rating, as the item ID twain is used to identify the rating via its id attribute (twain-rating).

Next up are the stars themselves, which are all coded as li list elements:

   <li><a href="javascript:setRating('twain', 1);"
     class="one-star">1</a></li>
   <li><a href="javascript:setRating('twain', 2);"
     class="two-stars">2</a></li>
   <li><a href="javascript:setRating('twain', 3);"
     class="three-stars">3</a></li>
   <li><a href="javascript:setRating('twain', 4);"
     class="four-stars">4</a></li>
   <li><a href="javascript:setRating('twain', 5);"
     class="five-stars">5</a></li>

Each line of code here represents one of the five stars in a five-star rating. Not only does each star serve as a visual indication of a rating, but it also acts as a trigger for issuing a rating vote. This is evident in the fact that the setRating() function is called in response to each link within the list items. The setRating() function accepts as its first parameter the item ID for the rating, which in this case is twain, followed by the rating to be set. So the second parameter to the setRating() function is the number of stars to be set for the rating.

You're now ready to close up the main part of the rating component, like this:

  </ul>
</span>

The only remaining code is one last span element for the helper text that appears to the right of the rating:

<span id="twain-info" class="rating-info-small">
  (click to vote)</span>

Notice that this code uses the rating-info-small CSS style class, which corresponds to the small rating component. If you're creating a large rating component, change this style to rating-info.

This code also uses the item ID (twain) in the formation of the id attribute for the element (twain-info). Keep in mind that the purpose of this element is to instruct the user on how to cast a vote (prior to voting) and to display the total number of votes (after voting). A third role that the helper text plays is to display a status message while a vote is being stored on the server. This last role is very similar to the "loading" images you've seen in other examples, except in this case "loading" text is used instead.

That completes the breakdown of an individual rating component within the Rater Web page. If you look back at the rating code used throughout the page, you'll see five distinct chunks of code that exactly follow the structure you just examined.

The only loose end remaining in the Rater application is the call to the initRatings() function, which must be made in the onload event handler for the page's body. This is the function that initially sets the values for all of the ratings on the page. Without this function, the benefit of writing the ratings to a file on the server would be lost.

The Cookie Reset Web Page

The Cookie Reset Web page (cookiereset.html) is a helper tool for the Rater application that is used to reset the cookies and allow you to vote again on any of the quotations on the Rater page. This is helpful for testing out the application and experimenting with different ratings without having to get access to a bunch of unique computers. Of course, you would never publish the Cookie Reset Web page so that it is accessible to other users; it is purely an internal tool to use for your own testing.

Figure 12.5 shows the Cookie Reset Web page in action, which admittedly isn't very exciting at all.

Figure 12.5. The Cookie Reset Web page displays a quick message to let you know that the Rater cookies have been reset.

[View full size image]

The lack of excitement in the Cookie Reset Web page stems from the fact that it doesn't do anything beyond clearing the value of the five cookies associated with the five quotation ratings. Following is the complete HTML code for the page, cookiereset.html, which should illuminate the cookie-clearing process:

<html>
  <head>
    <title>Rater - Cookie Reset</title>
    <script type="text/javascript">
      document.cookie = "twain-rating=";
      document.cookie = "einstein-rating=";
      document.cookie = "ali-rating=";
      document.cookie = "paine-rating=";
      document.cookie = "shaw-rating=";
    </script>
  </head>

 <body>
   <p>The cookies are reset.</p>
 </body>
</html>

As you can see, the five cookies are cleared in the head of the page. Clearing a cookie simply involves setting the cookie to nothing. It's extremely important to get the name of each cookie correct, and in this case I stuck with the naming convention established in the Rater application where the quotation ID is placed in front of the text–rating to arrive at the cookie name.

Keep in mind that the Cookie Reset Web page is really just a time-saving tool. Your Web browser likely includes an option for clearing all of the cookies it has amassed. However, some browsers only offer an option to clear all cookies. Even when there is an option to clear individual cookies, it can be extremely tedious hunting down the rating cookies when you consider that you likely have hundreds of cookies stored in your browser at any given time.

Note

You will likely end up using different item IDs when reusing the rating component in your own Web pages, in which case you'll want to modify the Cookie Reset page so that it clears your new cookies.


ch12lev1sec4.html

Testing Rater

The Rater application makes for a fairly interesting application to test because it involves data that is stored away on the server, meaning that the application maintains a certain state. This is another way of saying that it remembers the votes that have been made. Also keep in mind that the application is designed to prevent more than one vote on a particular item from a given computer. So to test the application thoroughly on one computer, you'll need to use the cookiereset.html Web page to reset the rating cookies created.

Figure 12.6 shows the Rater application with a clean slate (i.e., no votes have been cast for any of the ratings).

Figure 12.6. When you first launch the Rater application, all of the quotations are ready to be rated.

[View full size image]

Because no rating votes have been cast at this point, no cookies have been set, and therefore all of the ratings are available for voting. Hovering the mouse over one of the ratings allows you to see the potential rating by highlighting the light stars with darker stars (see Figure 12.7).

Figure 12.7. Hovering over a rating with the mouse allows you to preview the rating you're about to make.

[View full size image]

To finalize a rating for a particular item, just click the number of stars for the rating. This will result in the rating vote being cast, in which case the helper text beside the stars changes to indicate that the vote is being cast. Figure 12.8 shows this effect on the first rating component on the page, which corresponds to a quotation by Mark Twain.

Figure 12.8. Upon a rating vote being issued, the helper text next to the five-star rating changes to indicate that the vote is being cast.

[View full size image]

Once the vote is cast, the average rating for the item appears in the form of gold stars. This is significant because you aren't allowed to see the average rating until after casting your own vote. The total number of votes received for the item is also displayed in the helper text next to the stars. Figure 12.9 shows the Mark Twain quotation after receiving its first vote of four stars.

Figure 12.9. Upon a rating vote being successfully submitted, the rating component changes to reveal the average rating and the total number of votes.

[View full size image]

In addition to demonstrating the smaller five-star rating component, the Rater application also shows how to use a larger version with larger star images and related text. The Muhammad Ali quotation uses the larger version of the component—Figure 12.10 shows a vote being cast using this component.

Figure 12.10. The rating component also supports a larger version that uses both a larger star image and larger text.

[View full size image]

The real power of the Rater application and the rating component is many different people being able to rate items. Although the component is designed to prevent duplicate voting on the same machine through the use of a cookie, you can circumvent this by loading a special Web page that clears the rating cookies. If you open the cookiereset.html Web page in your browser, it will clear out all of the cookies for the Rater Web page, thereby allowing you to view the page as someone else would see it on his or her own computer.

Note

Make sure to refresh the Cookie Reset Web page if you end up using it more than once, and also refresh the Rater Web page after resetting the cookies. Otherwise, the cookie changes won't be noticeable.

Figure 12.11 shows the Rater application with several votes made on the quotations. In fact, the figure shows all of the rating averages, which means that a vote has been cast on every quotation.

Figure 12.11. By resetting the cookies, you can vote again on items and bypass the limitation of one vote per computer.

[View full size image]

The cool thing about the rating component is that it stores the ratings in a manner such that the XML file on the server doesn't grow when additional votes are cast. So as many people as you want can vote on items without you having to worry about a rating data file growing out of control.


ch12lev1sec5.html

Giving Rater an Extreme Ajax Makeover

There are a variety of different ways to expand on the Rater application, but the most likely thing you'll want to do first is apply the rating component to your own Web pages. I'm assuming you have some items in mind that you'd like to add the capability of rating on a five-star scale. These items can be images, music clips, videos, text, or anything else you dream up. The main thing is that you need to be able to add the rating component HTML code somewhere near the item on the page so that it can be easily accessed.

The first step in adding the rating component to a page of your own is to import the appropriate Ajax Toolkit files. The following code needs to be added to the head of the page that will contain the ratings:

<link rel="stylesheet" type="text/css" href="ratingkit.css" />
<script type="text/javascript" src="ajaxkit.js"> </script>
<script type="text/javascript" src="domkit.js"> </script>
<script type="text/javascript" src="ratingkit.js"> </script>

This code imports the rating CSS style sheet along with several JavaScript files that are all required in order for the rating component to work. The next thing to do is to call the initRatings() function from the onload event handler in the <body> tag, like this:

<body onload="initRatings()">

This makes sure that all of the ratings on the page get initialized properly.

From here on, the code largely depends on how you want to structure the ratings. Let's say you have lots of products in an online store that you'd like to rate. In this case, you'll want to use an item ID for the ratings that somehow ties into an existing product ID. This is likely a number of some sort, along the lines of a retail UPC code or Amazon.com's ASIN numbers, which the company uses to uniquely identify products. Let's assume for simplicity that your products are simple integers that start at 1 and count up. So your products are numbered 1, 2, 3, 4, and so on.

You now have an item ID to uniquely identify the rating for each item, which is all you need to add the ratings to your page. Here's the code for a small rating for the first product (item ID of 1):

<div>
  <span class="rating-label-small">Rating:</span>
  <span class="inline-rating">
    <ul class="star-rating small-star">
      <li id="1-rating" class="current-rating"
        style="width:0%">Rating</li>
      <li><a href="javascript:setRating('1', 1);"
        class="one-star">1</a></li>
      <li><a href="javascript:setRating('1', 2);"
        class="two-stars">2</a></li>
      <li><a href="javascript:setRating('1', 3);"
        class="three-stars">3</a></li>
      <li><a href="javascript:setRating('1', 4);"
        class="four-stars">4</a></li>
      <li><a href="javascript:setRating('1', 5);"
        class="five-stars">5</a></li>
    </ul>
  </span>
  <span id="1-info" class="rating-info-small">
    (click to vote)</span>
</div>

Do you see the pattern in the code? The item ID appears in exactly seven places, and all of them are important. The first place the item ID appears is in the id attribute of the <li> list item tag, which is set to 1-rating. The next five appearances are in the calls to the setRating() function for each of the possible votes (one star through five stars). In this case, the value '1' is passed into the function as its first parameter; this is the item ID. Finally, the item ID is referenced once more as 1-info in the id attribute of the <span> element near the end of the code. This is what ties the helper text for the rating component to the particular item.

All of these item ID references must be set properly for each individual rating in a page. Just to make sure you understand how this works, let's fast-forward through the product catalog a bit until we arrive at the product with an item ID of 379. Here's the code to add a rating component for this item:

<div>
  <span class="rating-label-small">Rating:</span>
  <span class="inline-rating">
    <ul class="star-rating small-star">
      <li id="379-rating" class="current-rating"
        style="width:0%">Rating</li>
      <li><a href="javascript:setRating('379', 1);"
        class="one-star">1</a></li>
      <li><a href="javascript:setRating('379', 2);"
        class="two-stars">2</a></li>
      <li><a href="javascript:setRating('379', 3);"
        class="three-stars">3</a></li>
      <li><a href="javascript:setRating('379', 4);"
        class="four-stars">4</a></li>
      <li><a href="javascript:setRating('379', 5);"
        class="five-stars">5</a></li>
    </ul>
  </span>
  <span id="379-info" class="rating-info-small">
    (click to vote)</span>
</div>

Hopefully this code hammers home the placement of the item ID in the code for a rating. You can paste this chunk of code as many times as you want to create different ratings, as long as you are careful to change the item ID each time.

Note

One other quick rating makeover that is extremely easy to apply is changing out the star images with images of your own. The large and small star images are stored in the files star.gif and star_sm.gif, respectively. Each of these files contains three different stars that are required for the hover effect. The stars are arranged vertically in the GIF image, and are all the same size (25x25 for large and 10x10 for small). If you use images that are the same size and arrange them vertically in the same manner, you can easily change the entire look of the rating component—just copy your own star image file over star.gif and/or star_sm.gif.

Reusing the rating component in your own pages isn't the only extreme makeover worth considering. Although the rater component works great as is, you may not be fully satisfied with the usage of an XML file for storing the rating data on the server. I opted for this approach primarily because I didn't want to make the application any more complex than necessary, and adding a database into the mix is a fair amount of additional complexity. But it's not a bad idea.

If you have some experience with MySQL or some other database, you might consider reworking the ratingkit.php server script so that it reads and writes rating data using a database instead of an XML file. Rather than get into the actual coding details of an implementation in MySQL, I'll just paint you a general picture of how this can be done.

In short, the following steps are required to change the rating component in the Ajax Toolkit so that it uses a MySQL database for rating storage and retrieval instead of an XML file:

  1. Create a database table named rating with the following fields: id, avg, and votes. These fields map one-to-one with the tags of the same name in the ratings.xml file.

  2. Change ratingkit.php so that it establishes a database connection instead of opening an XML file.

  3. Change ratingkit.php so that it reads all of the rows from the rating table via a database query instead of reading in the ratings.xml file.

  4. Change ratingkit.php so that all of the code that iterates through the ratings in the XML data structure instead iterates through the rows returned from the database query.

  5. Change ratingkit.php so that it modifies the appropriate row in the rating table to store a rating instead of writing out the XML file.

I realize this list of steps is incredibly generalized and requires a fair amount of MySQL experience to carry out. But in all honesty, that's kind of the point—I'd rather see you stick with the XML file solution if you don't have the MySQL skills to pull this off. Trust me, this is a very basic database challenge to anyone with database skills. If you're short on database skills, as many of us are, just roll with the XML version knowing that it should meet your needs just fine.


ch12lev1sec6.html

Summary

Although you may not always like the feedback you get, it's hard to argue the benefits of allowing users the freedom to rate content on your site. Ratings provide one of the key features of any interactive online community, and help people feel more involved and more informed. The Ajax rating component you learned how to use in this chapter is flexible enough to support any number of individually rated items, as well as sports a highly intuitive user interface for submitting a rating in the range of one to five stars. And you don't even have to be a database guru to start using ratings thanks to the fact that a simple XML file is used for storing ratings on the server. If you do happen to be a database guru, however, you may want to consider applying the extreme Ajax makeover ideas to incorporate the rating storage into your own database.


part03.html

Part III: Appendices

Appendix A The Past, Present, and Future of Ajax

Appendix B A Quick and Dirty XMLHttpRequest Reference

Appendix C Using the Live Linux CD

Appendix A. The Past, Present, and Future of Ajax

Maybe you couldn't care less where Ajax came from, but just in case you do, I thought a little history lesson might be worthwhile. By understanding a bit more about the origins of Ajax, you'll hopefully be more capable of assessing the role it will play in the future of Web development. It's a very exciting technology, but one that is in many ways still in an exploratory state. So where exactly did Ajax come from and where is it headed? Let's find out.

The Road to Ajax

When you get right down to it, Ajax is really just a term used to describe a particular application of existing technologies. This particular application has been around for a few years, but not until February of 2005 was given a catchy name. The man responsible for the name is Jesse James Garrett, who needed a more efficient way to describe a Web solution to a client of his employer, Adaptive Path. The name Ajax hit Garrett one day in the shower, and it stuck. People began thinking that Ajax was actually an acronym (AJAX) that stood for Asynchronous JavaScript and XML, but this isn't entirely the case. Although the name Ajax does in fact refer to a development approach involving asynchronous JavaScript and XML, the word "Ajax" isn't strictly an acronym.

Surprisingly enough, the road leading up to Garrett's catchy name can be traced back to Microsoft's Remote Scripting technology, which was officially introduced in 1998 in Internet Explorer 4 and Netscape Navigator 4. A functional application that utilized Microsoft's Remote Scripting technology was Outlook Web Access, which was certainly pioneering for its time. Taking a step back a few years earlier, the iframe (Internet Explorer) and layer (Netscape Navigator) elements supported the asynchronous loading of Web content as far back as 1996. The iframe and layer elements in combination with crafty JavaScript coding ushered in the notion of Dynamic HTML, or DHTML, which was popular for several years prior to the advent of Ajax techniques.

The true birth of Ajax took place in 2000 when Microsoft added the XMLHTTPRequest object to Internet Explorer 5. It still took a few years for the technology to mature to a point where it could be used consistently, and even then it took a groundbreaking application for everyone to truly see the power of Ajax.


app01.html

Part III: Appendices

Appendix A The Past, Present, and Future of Ajax

Appendix B A Quick and Dirty XMLHttpRequest Reference

Appendix C Using the Live Linux CD

Appendix A. The Past, Present, and Future of Ajax

Maybe you couldn't care less where Ajax came from, but just in case you do, I thought a little history lesson might be worthwhile. By understanding a bit more about the origins of Ajax, you'll hopefully be more capable of assessing the role it will play in the future of Web development. It's a very exciting technology, but one that is in many ways still in an exploratory state. So where exactly did Ajax come from and where is it headed? Let's find out.

The Road to Ajax

When you get right down to it, Ajax is really just a term used to describe a particular application of existing technologies. This particular application has been around for a few years, but not until February of 2005 was given a catchy name. The man responsible for the name is Jesse James Garrett, who needed a more efficient way to describe a Web solution to a client of his employer, Adaptive Path. The name Ajax hit Garrett one day in the shower, and it stuck. People began thinking that Ajax was actually an acronym (AJAX) that stood for Asynchronous JavaScript and XML, but this isn't entirely the case. Although the name Ajax does in fact refer to a development approach involving asynchronous JavaScript and XML, the word "Ajax" isn't strictly an acronym.

Surprisingly enough, the road leading up to Garrett's catchy name can be traced back to Microsoft's Remote Scripting technology, which was officially introduced in 1998 in Internet Explorer 4 and Netscape Navigator 4. A functional application that utilized Microsoft's Remote Scripting technology was Outlook Web Access, which was certainly pioneering for its time. Taking a step back a few years earlier, the iframe (Internet Explorer) and layer (Netscape Navigator) elements supported the asynchronous loading of Web content as far back as 1996. The iframe and layer elements in combination with crafty JavaScript coding ushered in the notion of Dynamic HTML, or DHTML, which was popular for several years prior to the advent of Ajax techniques.

The true birth of Ajax took place in 2000 when Microsoft added the XMLHTTPRequest object to Internet Explorer 5. It still took a few years for the technology to mature to a point where it could be used consistently, and even then it took a groundbreaking application for everyone to truly see the power of Ajax.


app01lev1sec1.html

Part III: Appendices

Appendix A The Past, Present, and Future of Ajax

Appendix B A Quick and Dirty XMLHttpRequest Reference

Appendix C Using the Live Linux CD

Appendix A. The Past, Present, and Future of Ajax

Maybe you couldn't care less where Ajax came from, but just in case you do, I thought a little history lesson might be worthwhile. By understanding a bit more about the origins of Ajax, you'll hopefully be more capable of assessing the role it will play in the future of Web development. It's a very exciting technology, but one that is in many ways still in an exploratory state. So where exactly did Ajax come from and where is it headed? Let's find out.

The Road to Ajax

When you get right down to it, Ajax is really just a term used to describe a particular application of existing technologies. This particular application has been around for a few years, but not until February of 2005 was given a catchy name. The man responsible for the name is Jesse James Garrett, who needed a more efficient way to describe a Web solution to a client of his employer, Adaptive Path. The name Ajax hit Garrett one day in the shower, and it stuck. People began thinking that Ajax was actually an acronym (AJAX) that stood for Asynchronous JavaScript and XML, but this isn't entirely the case. Although the name Ajax does in fact refer to a development approach involving asynchronous JavaScript and XML, the word "Ajax" isn't strictly an acronym.

Surprisingly enough, the road leading up to Garrett's catchy name can be traced back to Microsoft's Remote Scripting technology, which was officially introduced in 1998 in Internet Explorer 4 and Netscape Navigator 4. A functional application that utilized Microsoft's Remote Scripting technology was Outlook Web Access, which was certainly pioneering for its time. Taking a step back a few years earlier, the iframe (Internet Explorer) and layer (Netscape Navigator) elements supported the asynchronous loading of Web content as far back as 1996. The iframe and layer elements in combination with crafty JavaScript coding ushered in the notion of Dynamic HTML, or DHTML, which was popular for several years prior to the advent of Ajax techniques.

The true birth of Ajax took place in 2000 when Microsoft added the XMLHTTPRequest object to Internet Explorer 5. It still took a few years for the technology to mature to a point where it could be used consistently, and even then it took a groundbreaking application for everyone to truly see the power of Ajax.


app01lev1sec2.html

The Ajax Boom

Major technological shifts rarely happen in the abstract. In the case of Ajax, it took a real-world example to demonstrate how compelling the technology could be. That example was and still is Google Maps. Released to the world in beta form in February of 2005, Google Maps boggled the minds of many Web developers who marveled at how the map could be dragged in real time. How could it be possible for that much data to be transferred so fast? As it turned out, it was a very clever usage of Ajax that allowed Google Maps to appear so responsive. In reality, the application attempts to anticipate your next move and preloads map data asynchronously.

Note

It's worth noting that the social networking site Orkut was technically the first mainstream application of Ajax, but it had nowhere near the shock and awe of Google Maps. Orkut used (and continues to use) Ajax to allow users to rate their friends with a star rating system.

In my mind at least, Google Maps formally ushered in the Ajax era of Web applications. The stampede began, and now numerous mainstream applications have an Ajax feel that is unmistakable. Gmail, Flickr, and Netflix are but a few of the other mainstream applications that are now heavily injected with Ajax, never to return to the land of click, wait, reload. With the huge momentum behind the technology, we will no doubt see many more applications become Ajax-powered as time goes by.


app01lev1sec3.html

What's Next for Ajax?

In lieu of the rapid ascent of Ajax, it is worth putting things into perspective as we chart a path into the future. One thing for certain is that many of us in the tech industry still have not learned our lesson from the dot-com bubble bursting of the late 90s. The term "irrational exuberance" has been used to describe the mentality that lead to unchecked rises in tech stocks during that period. A big part of the problem had to do with people latching on to the next "big idea" as if it was going to change the world as we know it. Of course the Internet as a whole has changed the world a fair amount, but many of us have a tendency to hype each new advance as if it alone holds the promise of unimaginable progress, efficiency, riches, etc. Ajax is one of these new advances.

When observed with a bit more perspective, it becomes apparent that Ajax is but one advance in the evolution of the Web. I'm not attempting to understate the significance of the advance, but I am cautioning that we all shouldn't get carried away in the excitement of the newness. Ajax indeed offers the promise of a more responsive and ultimately more usable Web, and that is worthy of some excitement. But at the same time, let's not forget that it solves a very specific problem that isn't necessarily an issue with every Web application. Ajax is not a magic bullet that you fire at every Web page you develop.

As we venture into the uncharted future of the Web plus Ajax, the degree to which we restrain the usage of Ajax may ultimately play a critical role in Ajax's continued success. This has to do with a variety of reasons, one of which is the fact that Ajax can actually put more of a workload on servers despite the fact that less information is typically being transferred. Sure, you've eliminated an entire page of data being sent with each request, but you've opted to fire off a couple dozen requests instead of just one. Depending on the specific server configuration, multiple small requests can potentially present more of a bottleneck than a single large request.

All this is to say that you should approach future Web projects knowing that Ajax is an incredibly handy tool, but it's ultimately still just a tool. The old saying that to a hammer every problem looks like a nail certainly applies here. Just because you have the knowledge and code to inject Ajax into everything you do doesn't necessarily make it right. At the same time, even the smallest properly structured Ajax application can be incredibly compelling and dramatically improve the usability of the app. If we all use Ajax with a tiny bit of creative restraint, the Web of the future will certainly be a more enjoyable place to live and work.


app02.html

Appendix B. A Quick and Dirty XMLHttpRequest Reference

Although the major premise of this book is to empower you to use Ajax without having to immerse yourself in the nitty-gritty details of asynchronous JavaScript coding, you may get motivated enough by the examples to dive into Ajax programming. If so, you will need to understand the XMLHttpRequest object inside and out—this object houses the primary functionality responsible for making Ajax work. This appendix provides you with a concise reference to the XMLHttpRequest object, along with a few helpful hints about how to best use its methods and properties. For a complete reference on all of the objects supported by the core JavaScript language, please refer to http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference.

Methods

The XMLHttpRequest object contains several methods used to establish a connection with a Web server and send and receive data. Although the modern usage of the object typically involves asynchronous communication, the object is perfectly capable of performing synchronous operations as well. It's how you use the methods of the object that determines the nature of a particular request.

Following are the main methods supported by the XMLHttpRequest object:

  • open()

  • send()

  • abort()

  • overrideMimeType()

  • setRequestHeader()

  • getAllResponseHeaders()

  • getResponseHeader()

Of these methods, the first two are by far the most important and most commonly used. The next few sections explore these methods in more detail.

open()

open(method, url[, async[, userName[, password]]])

The open() method opens a server request and prepares it for impending communication. The two required parameters (method and url) specify the request method and URL of the server connection, respectively. The request method parameter can be either "GET" or "POST", depending on whether you are making a fairly simple data retrieval request ("GET") or needing to send a fair amount of data to the server as part of the request ("POST"). You can still use the GET method if you're just sending along a few pieces of information, but for larger data-submission requests (greater than 512 bytes), POST is your best bet.

Tip

Another handy way to know when to use GET or POST as the request method for an Ajax request is to assess whether or not data will change on the server based upon the request. If the state of the server changes due to the request, then POST is the answer; otherwise, go with GET.

The url parameter may be specified as an absolute (full) or relative URL, but keep in mind that in either case the URL must match that of the JavaScript code generating the request. In other words, an Ajax connection can only make a request on the same server as the Ajax script code itself. This is a security limitation of the XMLHttpRequest object, but one that is designed to protect users from malicious Ajax coders.

The third parameter to the open() method, async, is an optional Boolean value that determines whether or not the request is handled asynchronously. The default value of true indicates an asynchronous (Ajax) request, whereas false indicates a synchronous request. In practice, this means that a synchronous request makes your script wait for a response before doing anything else, whereas an asynchronous request takes place in the background, only reporting back when it's finished. In a few rare situations, a synchronous request might make sense, such as when waiting for absolutely critical data before allowing the user to proceed with a task, but in the vast majority of cases, you'll want to go with an asynchronous request. Besides, asynchronicity is what makes Ajax so cool.

Note

Most browsers that support Ajax limit Ajax requests to HTTP requests (http: protocol), which means you won't be able to test an Ajax script from your local hard drive using the file: protocol. Of course, you can always install a Web server locally, in which case you can use the http: protocol to open Ajax pages.

The last two parameters to open() are entirely optional, and are ultimately dependent upon whether your server requires a username and password in order to carry out the request.

Following is a simple example of creating an XMLHttpRequest object and calling the open() method to establish an asynchronous request:

var request = new XMLHttpRequest;
request.open("GET", "processSomeStuff.php", true);

Two aspects of the XMLHttpRequest object are closely tied to the open() method: the send() method and the onreadystatechange event handler. The send() method must be called after the open() method in order to actually carry out an Ajax request. The onreadystatechange event is assigned a callback method of your own that gets automatically called when the Ajax request completes. In other words, you must write your own function that will get called whenever an Ajax request finishes doing its job. This function is where you process the data returned from the completed Ajax request.

send()

send(content)

The send() method is responsible for actually sending a request to a server for processing. The connection must have already been prepared with a call to open() prior to send() being called. The single parameter to the send() method, content, is data to be sent to the server as part of the request. In many cases you will be strictly making a server request without sending any data, in which case it is perfectly acceptable to pass null into the send() method, like this:

request.send(null);

Passing null to the send() method is often done when using the "GET" request method. The "POST" method, on the other hand, is designed specifically for passing along data to the server, in which case you'll want to include meaningful data in the content parameter.

Content passed into the send() method via the content parameter can be a string, an array of unsigned bytes, or an XML DOM object. In many cases you'll just pass a string into the method, in which case it usually takes the familiar POST-style name/value pair, like in this example:

request.send("artist=phish&album=rift&track=weigh");

It's important to note that for asynchronous requests you'll need to set the onreadystatechange event handler before calling the send() method. Otherwise, your event handler callback method will never get called and the Ajax effect will be entirely lost. Following is an example of how this handler is set, which must take place prior to calling the send() method:

request.onreadystatechange = yourHandler;

Keep in mind that when the Ajax request finishes, a call is automatically made to the yourHandler() function so that you can do something useful with the data returned by the request.

abort()

abort()

The abort() method stops the server request. This method can be handy in a timeout situation when you elect to give up on a lengthy request. You can also call the abort() method to make sure that the request object is reset before reusing it to carry out another request. Following is an example of calling the abort() method to terminate an Ajax request:

request.abort();

overrideMimeType()

overrideMimeType(type)

The overrideMimeType() method provides you with a means of overruling the MIME type of the data returned from the server in response to a request. This can be handy in situations where you are expecting XML but for some reason can't get the server to cooperate. For example, the server may be rejecting XML data because it isn't perfectly well-formed, in which case the server is returning the data as raw text via the responseText property. If you call the overrideMimeType() method and specify "text/xml" as the MIME type, the server will attempt to return XML data in the responseXML property:

request.overrideMimeType("text/xml");

Note

The overrideMimeType() method should be called after you call the open() method but before calling the send() method.

setRequestHeader()

setRequestHeader(label, value)

The setRequestHeader() method is used to add a label/value pair to the request header. This method is not necessary for normal GET requests but is essential when making POST requests. For example, the following request header setting lets the server know that the data in a POST request is going to be in the form of an encoded URL:

request.setRequestHeader("Content-Type",
  "application/x-www-form-urlencoded");

XML is another popular data format for issuing a POST request. If you plan on passing XML data to the server in a POST request, then the following request header setting is necessary:

request.setRequestHeader("Content-Type",
  "text/xml");

The need to set the request header ultimately depends upon your specific request. If your request is a POST, you should always set it. Otherwise, in the case of a GET, you should be just fine without setting anything on the request header.

getAllResponseHeaders()

getAllResponseHeaders()

The getAllResponseHeaders() method returns all of the response headers associated with the response as a string containing a series of newline-separated label/value pairs. Of perhaps a bit more use is the getResponseHeader() method, which returns a single value for a particular header label.

getResponseHeader()

getResponseHeader(headerLabel)

The getResponseHeader() method accepts the label of a specific header and returns the string value of the header for that label. As an example, you can determine the content type of a request by getting the response header for the "Content-Type" label, like this:

var header = request.getResponseHeader("Content-Type");

In this example, the return value stored in the header variable might be something along the lines of text/xml or text/plain, depending upon the type of data returned by the request.


app02lev1sec1.html

Appendix B. A Quick and Dirty XMLHttpRequest Reference

Although the major premise of this book is to empower you to use Ajax without having to immerse yourself in the nitty-gritty details of asynchronous JavaScript coding, you may get motivated enough by the examples to dive into Ajax programming. If so, you will need to understand the XMLHttpRequest object inside and out—this object houses the primary functionality responsible for making Ajax work. This appendix provides you with a concise reference to the XMLHttpRequest object, along with a few helpful hints about how to best use its methods and properties. For a complete reference on all of the objects supported by the core JavaScript language, please refer to http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference.

Methods

The XMLHttpRequest object contains several methods used to establish a connection with a Web server and send and receive data. Although the modern usage of the object typically involves asynchronous communication, the object is perfectly capable of performing synchronous operations as well. It's how you use the methods of the object that determines the nature of a particular request.

Following are the main methods supported by the XMLHttpRequest object:

  • open()

  • send()

  • abort()

  • overrideMimeType()

  • setRequestHeader()

  • getAllResponseHeaders()

  • getResponseHeader()

Of these methods, the first two are by far the most important and most commonly used. The next few sections explore these methods in more detail.

open()

open(method, url[, async[, userName[, password]]])

The open() method opens a server request and prepares it for impending communication. The two required parameters (method and url) specify the request method and URL of the server connection, respectively. The request method parameter can be either "GET" or "POST", depending on whether you are making a fairly simple data retrieval request ("GET") or needing to send a fair amount of data to the server as part of the request ("POST"). You can still use the GET method if you're just sending along a few pieces of information, but for larger data-submission requests (greater than 512 bytes), POST is your best bet.

Tip

Another handy way to know when to use GET or POST as the request method for an Ajax request is to assess whether or not data will change on the server based upon the request. If the state of the server changes due to the request, then POST is the answer; otherwise, go with GET.

The url parameter may be specified as an absolute (full) or relative URL, but keep in mind that in either case the URL must match that of the JavaScript code generating the request. In other words, an Ajax connection can only make a request on the same server as the Ajax script code itself. This is a security limitation of the XMLHttpRequest object, but one that is designed to protect users from malicious Ajax coders.

The third parameter to the open() method, async, is an optional Boolean value that determines whether or not the request is handled asynchronously. The default value of true indicates an asynchronous (Ajax) request, whereas false indicates a synchronous request. In practice, this means that a synchronous request makes your script wait for a response before doing anything else, whereas an asynchronous request takes place in the background, only reporting back when it's finished. In a few rare situations, a synchronous request might make sense, such as when waiting for absolutely critical data before allowing the user to proceed with a task, but in the vast majority of cases, you'll want to go with an asynchronous request. Besides, asynchronicity is what makes Ajax so cool.

Note

Most browsers that support Ajax limit Ajax requests to HTTP requests (http: protocol), which means you won't be able to test an Ajax script from your local hard drive using the file: protocol. Of course, you can always install a Web server locally, in which case you can use the http: protocol to open Ajax pages.

The last two parameters to open() are entirely optional, and are ultimately dependent upon whether your server requires a username and password in order to carry out the request.

Following is a simple example of creating an XMLHttpRequest object and calling the open() method to establish an asynchronous request:

var request = new XMLHttpRequest;
request.open("GET", "processSomeStuff.php", true);

Two aspects of the XMLHttpRequest object are closely tied to the open() method: the send() method and the onreadystatechange event handler. The send() method must be called after the open() method in order to actually carry out an Ajax request. The onreadystatechange event is assigned a callback method of your own that gets automatically called when the Ajax request completes. In other words, you must write your own function that will get called whenever an Ajax request finishes doing its job. This function is where you process the data returned from the completed Ajax request.

send()

send(content)

The send() method is responsible for actually sending a request to a server for processing. The connection must have already been prepared with a call to open() prior to send() being called. The single parameter to the send() method, content, is data to be sent to the server as part of the request. In many cases you will be strictly making a server request without sending any data, in which case it is perfectly acceptable to pass null into the send() method, like this:

request.send(null);

Passing null to the send() method is often done when using the "GET" request method. The "POST" method, on the other hand, is designed specifically for passing along data to the server, in which case you'll want to include meaningful data in the content parameter.

Content passed into the send() method via the content parameter can be a string, an array of unsigned bytes, or an XML DOM object. In many cases you'll just pass a string into the method, in which case it usually takes the familiar POST-style name/value pair, like in this example:

request.send("artist=phish&album=rift&track=weigh");

It's important to note that for asynchronous requests you'll need to set the onreadystatechange event handler before calling the send() method. Otherwise, your event handler callback method will never get called and the Ajax effect will be entirely lost. Following is an example of how this handler is set, which must take place prior to calling the send() method:

request.onreadystatechange = yourHandler;

Keep in mind that when the Ajax request finishes, a call is automatically made to the yourHandler() function so that you can do something useful with the data returned by the request.

abort()

abort()

The abort() method stops the server request. This method can be handy in a timeout situation when you elect to give up on a lengthy request. You can also call the abort() method to make sure that the request object is reset before reusing it to carry out another request. Following is an example of calling the abort() method to terminate an Ajax request:

request.abort();

overrideMimeType()

overrideMimeType(type)

The overrideMimeType() method provides you with a means of overruling the MIME type of the data returned from the server in response to a request. This can be handy in situations where you are expecting XML but for some reason can't get the server to cooperate. For example, the server may be rejecting XML data because it isn't perfectly well-formed, in which case the server is returning the data as raw text via the responseText property. If you call the overrideMimeType() method and specify "text/xml" as the MIME type, the server will attempt to return XML data in the responseXML property:

request.overrideMimeType("text/xml");

Note

The overrideMimeType() method should be called after you call the open() method but before calling the send() method.

setRequestHeader()

setRequestHeader(label, value)

The setRequestHeader() method is used to add a label/value pair to the request header. This method is not necessary for normal GET requests but is essential when making POST requests. For example, the following request header setting lets the server know that the data in a POST request is going to be in the form of an encoded URL:

request.setRequestHeader("Content-Type",
  "application/x-www-form-urlencoded");

XML is another popular data format for issuing a POST request. If you plan on passing XML data to the server in a POST request, then the following request header setting is necessary:

request.setRequestHeader("Content-Type",
  "text/xml");

The need to set the request header ultimately depends upon your specific request. If your request is a POST, you should always set it. Otherwise, in the case of a GET, you should be just fine without setting anything on the request header.

getAllResponseHeaders()

getAllResponseHeaders()

The getAllResponseHeaders() method returns all of the response headers associated with the response as a string containing a series of newline-separated label/value pairs. Of perhaps a bit more use is the getResponseHeader() method, which returns a single value for a particular header label.

getResponseHeader()

getResponseHeader(headerLabel)

The getResponseHeader() method accepts the label of a specific header and returns the string value of the header for that label. As an example, you can determine the content type of a request by getting the response header for the "Content-Type" label, like this:

var header = request.getResponseHeader("Content-Type");

In this example, the return value stored in the header variable might be something along the lines of text/xml or text/plain, depending upon the type of data returned by the request.


app02lev1sec2.html

Properties

Methods are only half of the XMLHttpRequest equation. Several properties also come into play and are in fact quite important in successfully carrying out Ajax requests. Following are the most important properties supported by the XMLHttpRequest object:

  • readyState

  • status

  • statusText

  • responseText

  • responseXML

These properties are important because they tell you critical information about the status and state of Ajax requests, such as if a request is finished and successful, along with storing the data returned by Ajax requests. All of these properties are read-only, meaning that you can't set their values. The first three properties relate to the state and status of a request, whereas the last two properties are used to access the actual data returned from a request. The next few sections dig deeper into how these properties work.

readyState

The readyState property reflects the current state of a request and is your primary means of keeping track of the progress of the request. The property steps through a series of values as a request is carried out, with the last of these values indicating that the request has completed. Following are the possible values for the readyState property, in order of occurrence:

  • 0—Uninitialized

  • 1—Loading

  • 2—Loaded

  • 3—Interactive

  • 4—Complete

Of these property values, the last one is the only one you will typically be concerned with because it indicates the completion of a request. However, a value of 4 for the readyState property isn't the end of the story when it comes to detecting a successful Ajax request. You also need to consider the status property.

Note

The custom callback method assigned to the onreadystatechange event handler is called every time the value of the readyState property changes. This is why it is important to check for the readyState property equaling 4 in the callback method before taking action in response to a request—you need to confirm that the request has completed before doing anything.

status

The status property keeps up with the current HTTP server status, which can be one of many different values, including 404 for "Not Found" or 200 for "OK." Practically speaking, all you're really interested in from an Ajax perspective is a status setting of 200, which indicates that a request was carried out "OK." Plenty of other codes could feasibly pop up, but you're primarily interested in 200 because anything else means there was a problem.

You will typically check for the status property equaling 200 (OK) while also checking for the readyState property equaling 4 (Complete). If both properties check out, you know the request has completed successfully and you can begin processing the request data.

statusText

The statusText property contains a string message associated with the current status code. For example, the status text for the successful status code of 200 is "OK". You might consider displaying the status text for diagnostic or error-handling purposes should a request fail with a status code other than 200.

responseText

The responseText property is half of the property pair used to store the data returned from an Ajax request. I say it's half of the property pair because another property, called responseXML, is capable of returning data in a format different from responseText. If you plan on receiving request data as raw text, responseText is the property you'll want to use because it simply provides you with a string of text containing the data.

responseXML

The other half of the response data property pair is the responseXML property, which formats the return data from a request as a DOM-compatible XML document node object. Because the responseXML property provides you with a DOM node object, you can use all of the incredibly powerful and flexible DOM methods and properties to explore and manipulate the data. Although it is entirely possible and often useful to work with Ajax request data as raw text via the responseText property, it's the structure of XML request data supplied by responseXML that gives Ajax much of its power.

It's important to note that request data is only stored in the responseXML property when the response's content type is set to the XML MIME type, text/xml. In many cases the XML MIME type is automatically set correctly based upon the recognition of XML data in the response. However, this is not always the case, and you may run into a situation where the responseXML property is coming up empty even though you know the response is receiving XML data. The solution is to explicitly set the MIME type of the request to "text/xml" via the overrideMimeType() method.


app02lev1sec3.html

Events

The event that works all the magic behind the scenes in any Ajax application is onreadystatechange, which is triggered any time the ready state of a request changes. This event is typically assigned a custom event-handler method that takes action based upon a change in the ready state. It's your job to check and make sure within this method that the request completed (readyState == 4) and that it proceeded without error (status == 200).


app03.html

Appendix C. Using the Live Linux CD

A live CD is an entire computer operating system on a removable disc. The CD can be booted directly on most standard PCs, ignoring the contents of your hard drive, and run as a desktop, server, or other specialty kind of system. The Ajax Construction Kit live CD included with this book contains elements of all three. Using this live CD, you can run all the book's examples live, follow along with the code as you read the book, and modify the code to reuse later.

Inside the Live CD

The live CD is a remastered Ubuntu Linux live CD that has been adapted to include the following components:

  • Ajax Construction Kit examples— All the example applications described in this book are included on the live CD.

  • Web server— The XAMPP server is included on the live CD. With one click, you can start the server to try out the Ajax examples on your local computer or from another browser over the network.

  • Tools— The live CD also includes the Firefox Web browser (for displaying the examples) and Bluefish editor (for modifying the code). Because the CD is a full-featured, desktop live CD, other command-line tools and applications are also available to you.

  • Documentation— Links in the top panel let you access useful Ajax, PHP, and XAMPP documentation, in case you need reference material as you work with the code.

Using the Ajax Construction Kit CD as a live CD means that, after rebooting your PC, all the software you need to display, use, and modify the Ajax projects is available to you without any special configuration. However, in cases where you don't want to (or are not allowed to) reboot the PC you are working on, the live CD also offers other ways to work with the code.

On the CD we have included a version of the XAMPP Web server package that will easily install on Windows systems. Following the instructions for using that software and adding the code examples from the CD, you can run the Ajax projects from your Windows desktop. Everything you need is included on the CD. (You just need to do a bit more setup.)


app03lev1sec1.html

Appendix C. Using the Live Linux CD

A live CD is an entire computer operating system on a removable disc. The CD can be booted directly on most standard PCs, ignoring the contents of your hard drive, and run as a desktop, server, or other specialty kind of system. The Ajax Construction Kit live CD included with this book contains elements of all three. Using this live CD, you can run all the book's examples live, follow along with the code as you read the book, and modify the code to reuse later.

Inside the Live CD

The live CD is a remastered Ubuntu Linux live CD that has been adapted to include the following components:

  • Ajax Construction Kit examples— All the example applications described in this book are included on the live CD.

  • Web server— The XAMPP server is included on the live CD. With one click, you can start the server to try out the Ajax examples on your local computer or from another browser over the network.

  • Tools— The live CD also includes the Firefox Web browser (for displaying the examples) and Bluefish editor (for modifying the code). Because the CD is a full-featured, desktop live CD, other command-line tools and applications are also available to you.

  • Documentation— Links in the top panel let you access useful Ajax, PHP, and XAMPP documentation, in case you need reference material as you work with the code.

Using the Ajax Construction Kit CD as a live CD means that, after rebooting your PC, all the software you need to display, use, and modify the Ajax projects is available to you without any special configuration. However, in cases where you don't want to (or are not allowed to) reboot the PC you are working on, the live CD also offers other ways to work with the code.

On the CD we have included a version of the XAMPP Web server package that will easily install on Windows systems. Following the instructions for using that software and adding the code examples from the CD, you can run the Ajax projects from your Windows desktop. Everything you need is included on the CD. (You just need to do a bit more setup.)


app03lev1sec2.html

Running the Live CD

With an average PC, containing at least 256MB of RAM and a Pentium III, 650MHz (or better) processor, the live CD should perform quite well. Here's what you do:

  1. Insert the CD into a standard PC and reboot.

  2. Press Enter at the boot screen to select Start or Install.

  3. When the desktop appears after a few minutes (be patient), open the Start LAMPP icon to start the server.

  4. After the server is running, open the Start Projects icon to view and work with projects.

At this point you should see the Firefox Web browser open to the index page, from which you can run all the code examples in the book. The live CD's Ubuntu desktop, along with the Ajax Construction Kit components, appears in Figure C.1.

Figure C.1. The live CD provides easy access to launching the XAMPP Web server and exploring the Ajax example applications.

[View full size image]

If you want to start modifying the code examples, select the Bluefish icon in the top panel. The Bluefish editor (shown in the upper-right corner of Figure C.1) displays the Ajax code example files in the left column. You can change any of those files as you like. Then see the results live in your Firefox browser by reloading the page.

Besides the icon for the Bluefish editor, there are other useful icons in the top panel. Each of the small book icons in the panel represents a link to different support information. They include links to Ajax and related documentation and links to information on the XAMPP server.

The entire XAMPP server files are stored in the /opt/lampp folder. The code examples are stored in the /opt/lampp/htdocs folder. Any changes you make to the code or server settings that you want to keep must be saved before you shut down (which I'll discuss later). Without saving those files, the next time you reboot, the entire contents of your live CD system are returned to their original state.

Setting Up Networking

Many of the Ajax projects require Internet connectivity to work properly. Most wired Ethernet cards in Linux will be automatically detected and configured. If a DHCP server is available on the line, you will most likely be connected automatically and have immediate access to the Internet.

Wireless connectivity can be more challenging in Linux. Because many wireless cards require proprietary firmware from the manufacturer that cannot be legally redistributed with Linux, those wireless cards may require some extra work to get going in Linux. Other wireless cards won't work at all (although the number of completely unsupported cards has shrunk greatly in the past few years).

Whether wired or wireless, the first place to try setting up networking on the live CD is the Network Setup window. From the live CD desktop, select System, Administration, Networking. That window shows you immediately if your network interface hardware was detected and configured to run. You can go ahead and do any manual configuration of those interfaces (such as to set up a static IP address, if needed) that are shown as available.

If the Network Setup window tells you that your wireless card is not configured, open a Terminal window (from the Terminal icon in the top panel) to do a bit of detective work. Type the following command to try to determine the type of wireless card you are using:

$ lspci -v |grep -i wireless

You will likely see something like this after issuing the command:

02:02.0 Network controller: Intel Corporation PRO/Wireless
2200BG Network Connection (rev 05)

In this example, the wireless card is an Intel PRO/Wireless 2200BG card. With that information, go to your favorite search engine (presuming you have some machine to get you on the network or can temporarily hook up to a wired network) and search for the wireless card model and the word Linux (as in "Linux 2200BG"). This example turned up the ipw2200 driver project. I'll continue with that example. First I check to see if the driver had been loaded:

$ lsmod |grep ipw2200

A match for this command reveals that the driver has indeed been loaded:

ipw2200     115652   0

If the driver had not been installed, I would have to download (or otherwise get the driver on the machine) then load it using the modprobe command (such as sudo modprobe ipw2200). Next, I have to get the firmware needed by the card. Drivers for many wireless cards are in the /lib/firmware folder. If the firmware you need is not there, download the firmware and add it to the /lib/firmware folder.

At this point, you should be able to configure your wireless card. Select your wireless card from the Network Setup window and select the Properties window. Set up your wireless settings (ESSID, password, and configuration type, such as static or DHCP). Restart your network interfaces by typing sudo /etc/init.d/networking restart from a Terminal window. You should now be able to select the Network Monitor icon in the top panel to check the activity of your wireless card.

Backing Up Your Data

As I mentioned before, any changes you make during a live CD session will just disappear when you reboot, unless you back up your data in some way. You can back up your Ajax Construction Kit data to a local hard disk, to USB flash drive, or over the network. Then, the next time you start the live CD, you can restore that data. Here's an example of backing up data with a USB flash drive.

Insert the storage (such as a pen drive or a thumb drive) into a USB port. If it is formatted, the live CD should detect it and open any formatted partitions in a separate window on the desktop. Next, open the Archive Manager (select Applications, Accessories, Archive Manager). From the Archive Manager, select New and then add the name of the archive (such as AjaxProjects) and the folder to save it to (such as /media/usbdisk or other name representing your pen drive). Select New.

Open the Ajax Applications folder from the desktop. Then select some or all of the files and folders from that folder and drag and drop them on the Archive Manager window. The archive (tar and gzipped) is now saved on your USB drive.

The next time you boot your Ajax Construction Kit live CD, open the Archive Manager window again. Select Archive, Open and open the archive from your inserted USB drive. Select Edit, Select All to highlight all files in the archive. Then choose Archive, Extract.

Select Extract in Folder to choose the /opt/lampp/htdocs folder to extract the files to. With the defaults set, you will recreate folders and overwrite existing files. Make sure that is what you want to do. Then select Extract.

The procedure just described can also be used to copy your Ajax project files and folders to another computer system (such as a Windows box) to work on or run the projects from that machine. If that is the case, you may want to select an archive type such as .zip to make sure you can extract the files on the new system.

Note

If you want to backup the entire Web server (/opt/lampp), you might need to do so from the command line, instead of from the Archive Manager window. That's because you might need root permissions to access some of the files. Here's a command you could then use to backup the whole XAMPP server (including Ajax projects) to your USB disk. The second command lets you restore it:

$ sudo tar cvfz /media/usbdisk/lampp-backup.tar.gz /opt/lamp
$ cd / ; sudo tar xvfz /media/usbdisk/lampp-backup.tar.gz


app03lev1sec3.html

Running the Live CD Directly on a Windows PC

Some people may prefer not to reboot their computer to try the examples in this book. If that's your case, you can install the XAMPP server software on your Windows system and try the code examples from there. You won't get all the tools that come on the live CD, but you will be able to work from the Windows environment you are accustomed to.

To install and run the XAMPP server and code examples from this book on your Windows system, do the following:

  1. From your running Windows system, insert the live CD that comes with this book.

  2. Open the live CD in an Explorer window and navigate to the \Windows folder.

  3. From the CD's \Windows folder, open the XAMPP installer (xampp-win32-1.6.0a-installer.exe) and follow the installation instructions. It is made to run in Windows 2000, NT, and XP Professional. If you need help, refer to the XAMPP for Windows FAQ (www.apachefriends.org/en/faq-xampp-windows.html).

  4. If you chose all the defaults, the software will be extracted and you should end up with an XAMPP Control Panel desktop icon. Open that icon.

  5. When the XAMPP Control Panel Application window appears, select the Start buttons for Apache and MySql. (If Windows prompts you to unblock your ports, you don't need to if you just want to work with the server from your desktop.)

  6. Insert your Ajax Construction Kit CD into the CD drive and browse to the Windows folder (for example, D:\Windows).

  7. Open the Examples folder, choose Edit, Select All and Edit, Copy. Using your Explorer window, browse to the htdocs folder on the XAMPP window. This folder is on your hard disk and is likely something like C:\Program Files\xampp\htdocs. Then select Edit, Paste.

  8. With all the Ajax projects in place, you can start using them. From any Web browser on your machine, type this Web address to open the Ajax Construction Kit examples:

    http://localhost/index.html

You can use any text editors or Web content management tools you have on your Windows system to begin working with the Ajax projects.


app03lev1sec4.html

Running the Live CD Directly on a Mac PC

If you have an Intel-based Mac computer, you can run the live CD directly. However, you also have the option of running the Ajax code examples from Mac OS X instead using the included Apache software.

The live CD can be booted on the newer, Intel-based Mac computers (such as the Mac Mini) and used as described earlier in this appendix. Insert the live CD, reboot with the Alt key held down, and select to boot from the CD. (It will be noted as a Windows CD.) Your wired Ethernet card should work without any additional configuration. However, wireless Ethernet cards may not work in Linux from the computer. Otherwise, the live CD should work as it would on any Intel-based PC.

If you prefer to run the code examples natively in Mac OS X, you're in luck. Apache is included on new Mac systems, so you just need to do a bit of configuration, add the examples, and start the server. Here's how:

  1. Open a Terminal window, become root user (su -), and use any text editor to edit the /etc/httpd/httpd.conf file. You need to search for four lines and remove the comment character (#) in front of each of those lines to enable PHP and Perl for your Apache server. Here's what the lines look like after they have been uncommented:

    LoadModule perl_module  libexec/httpd/libperl.so
LoadModule php4_module  libexec/httpd/libphp4.so
AddModule mod_perl.c
AddModule mod_php4.c

    Close the Terminal window and return to the OS X desktop.

  2. Insert the live CD, then open the Windows, Examples folder from the CD. You should see all the Ajax code example files and folders.

  3. Open a file browser (select the Macintosh HD icon) and navigate to your home folder. From your home folder, open the Sites folder.

  4. Rename the existing index.html file in the Sites folder to some other name (such as index-original.html).

  5. Select everything from the Examples folder, then drag and drop that content to your Sites folder.

  6. Open the System Preferences folder and select the Sharing folder (under Internet & Network).

  7. From the Sharing window, select Personal Web Sharing. This will start the Apache Web server and begin serving the Ajax code examples.

  8. On the Sharing window, select the link shown after "...your personal website at..." which should look something like the following:

    http://10.0.0.1/~user

    Or you could type something like http://localhost/~user (where user is replaced by your user name) into the Web browser location box.

The Ajax code examples should appear in the browser window, ready to play.


app03lev1sec5.html

Running the Live CD in Other Ways

With the massive amount of open source and proprietary software available today, people have developed all kinds of ways to run software in different environments. If the live CD and Windows methods of working with the Ajax Construction Kit CD don't exactly suit you, here are some other ways you can set up the software from that CD to use with the book:

  • Windows desktop with emulator— Using virtualization software, such as VMPlayer (www.vmware.com) or QEMU (www.qemu.org), you can run the live CD as a virtual client. In effect, the live CD will be running in a window on your Windows or Linux desktop.

  • Your current Web server— You can copy the projects from the /Windows/Examples folder on the CD to your own Web server to run the code from there.

  • Any hard disk partition— If you have free space outside of your Windows or Linux partitions on your hard disk, you can install the entire contents of the live CD to your computer's hard disk. Unless you have some free disk space outside your existing disk partitions or you don't mind wiping out the contents of a hard disk on your computer, the process can be a bit tricky. That's because you will need to resize an existing disk partition to do it.

    Once you have an available disk or partition, however, the process of actually installing the live CD is quite easy. Just select the Install icon from the live CD desktop. The installer will step you through the process of installing the live CD so you can work with its contents from your hard disk.

  • Any Linux System— The full XAMPP stack and Ajax examples are included in a tar archive on the CD (/Linux/xampp-linux-1.6-Ajax.tar.gz). You can untar the contents of that archive to almost any Linux system that isn't already running a Web server and use the projects from that system. As root user, with the CD inserted, the following commands will untar the archive to your /opt folder and start the server:

    # cd /opt ; tar xvfz /media/disk/Linux/xampp-linux-1.6-Ajax.tar.gz
# /opt/lampp/lampp start

Keep in mind that the live CD is set up primarily as an educational tool for learning to write Ajax code. Although XAMPP can be used as a professional quality Web server, it is not currently configured for security. Before using the example code or Web server on a public network, be sure to take steps to lock down the security of that content.


index.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]


A.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

abort() method
age validator application
Ajax Construction Kit live CD
backing up data
contents
installing on hard drives
launching
network setup
overview
running as virtual client
running from Web server
running on Mac OS X
running on Windows PCs
tar archives
Ajax in pop culture
Ajax, Canada
Ajax character in movie The Warriors
Ajax cleanser
Ajax Corporation
Ajax Duckman (TV character)
Ajax the Greek hero
Ajax mountain
Ajax the racehorse
Ajax toilet
Ajax video game
USS Ajax
ajaxkit.js file 2nd 3rd 4th
Completer application
Forecaster application
Informer application
News Feeder application
Rater application
ajaxSendRequest() function 2nd 3rd
ajaxUpdateState() function
ajaxUpdateStatus() function
animated "loading" images
anticipating data entry [See Completer application (auto-completer).]
applications [See specific applications.]
asynchronous communications 2nd
Atom news feeds
auto-complete application [See Completer application (auto-completer).]


B.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

backing up
Ajax Construction Kit live CD data
XAMPP server
blogs, Booker application (e-book viewer)
<body> tag (HTML)
Completer application (auto-completer)
Forecaster application
Imaginator application
informer.html Web page
News Feeder application
Rater application
shipper.html Web page
snapper.html Web page
book_alicewonderland.xml file
book_frankenstein.xml file
book_mobydick.xml file
book_warofworlds file
<bookData> tag (XML)
Booker application (e-book viewer)
booker.html Web page 2nd 3rd
ajaxSendRequest() function
ajaxUpdateStatus() function
code listing
handleRequest() function 2nd
loadBook() function
loadChapter() function
nextChapter() function
prevChapter() function
replaceText() function
booker.php server script
client requests
client/server conversation
customizing
data-driven blog tool
e-book files
files 2nd
loading data in smaller chunks
overview
requests
server responses
testing
XML e-books
booker.html Web page 2nd 3rd
ajaxSendRequest() function
ajaxUpdateStatus() function
code listing
handleRequest() function 2nd
loadBook() function
loadChapter() function
nextChapter() function
prevChapter() function
replaceText() function
booker.php script


C.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

calculating shipping charges [See also Shipper application (shipping calculator).]
cascading style sheets [See CSS (cascading style sheets).]
CDs [See live CDs.]
<channel> tag (XML)
<chapter> tag (XML)
client/server conversations [See also requests;; responses.]
Completer application
Forecaster application
Informer application
News Feeder application
Picker application
Rater application
Shipper application
Validator application
commands, modprobe
COMPLETE state (requests)
Completer application (auto-completer)
ajaxkit.js file
challenges of anticipating data entry
client requests
client/server conversation
completer.html Web page 2nd
<body> tag
getCompletion() function
handleCompletionRequest() function
onkeyup event handler
onload event handler
showBiography() function
completer.php server script 2nd
context-sensitive search boxes
domkit.js file
overview
server responses
testing
user interface
when to use auto-complete
completer.html Web page 2nd
<body> tag
getCompletion() function
handleCompletionRequest() function
onkeyup event handler
onload event handler
showBiography() function
completer.php server script 2nd
configuring networking for Ajax Construction Kit live CD
context-sensitive search boxes
cookiereset.html Web page 2nd
CSS (cascading style sheets)
infowinkit.css file
newsfeeder.css style sheet 2nd
overview
ratingkit.css file
customizing Booker application (e-book viewer)


D.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

data entry, anticipating [See Completer application (auto-completer).]
<date> tag (XML)
<description> tag (XML)
diagnostic bar, turning on/off 2nd
documents (XML)
domkit.js file 2nd 3rd 4th
Completer application
Forecaster application
Imaginator application 2nd
Informer application
News Feeder application
Rater application
Duckman, Ajax (TV character)


E.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

e-book viewer [See Booker application (e-book viewer).]
<ebook> tag (XML)
elements (XML) [See tags (XML).]
embedding news feeds in Web pages
enabling diagnostic bar
event handlers
onload
onreadystatechange
event object
Extensible Markup Language [See XML (Extensible Markup Language).]


F.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

file_get_contents() function
files
Ajax toolkit
ajaxkit.js
domkit.js
infowinkit.js
modalimgkit.js
ratingkit.js
validatekit.js
Booker application 2nd
booker.html
customizing
e-book files
Completer application
completer.html
completer.php
Forecaster application
forecaster.html Web page
forecaster.php 2nd
Imaginator application 2nd
domkit.js file
modalimgkit.css file
modalimgkit.js file
modalimgkit_gray.png file
modalimgki_wait.gif file
Informer application
informer.html Web page
infowinkit.css file
infowinkit.js
infowinkit.js file
skateXXX.html Web pages
News Feeder application
newsfeeder.css style sheet
newsfeeder.html
newsfeeder.php
wait.gif
Picker application
Rater application
Validator application
XML files
five-star rating system [See Rater application (rating system).]
Flickr
Forecaster application (weather forecast window)
ajaxkit.js file
challenges of gathering dynamic weather information
changing city
client requests
client/server conversation
detailed weather reports
domkit.js file
forecaster.html Web page 2nd
forecaster.php server script 2nd 3rd
infowinkit.css file
infowinkit.js file
infowinkit_wait.gif file
overview
server responses
testing
user interface
forecaster.html Web page 2nd
forecaster.php server script 2nd 3rd
functions [See specific functions.]
future of Ajax


G.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

Garrett, Jesse James
getAllResponseHeaders() method
getCityState() function
getClientHeight() function
getClientLeft() function
getClientTop() function
getClientWidth() function
getCompletion() function
getCookieData() function
getElementById() function 2nd
getResponseHeader() method
getShipRate() function
getText() function
Gmail validation
Google
Gmail validation
Google Maps 2nd
Google Suggest 2nd


H.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

handleCityStateRequest() function
handleCompletionRequest() function
handleFeedRequest() function
handleRequest() function 2nd 3rd
handleStockInfoRequest() function
handleStockListRequest() function
hard drives, installing Ajax Construction Kit live CD on
Harrington, Sir John
history
of Ajax
of RSS
HTML (Hypertext Markup Language) [See specific pages (for example, newsfeeder.html).]
HTML (Hypertext Markup Language) tags [See tags (HTML).]


I.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

The Iliad
Imaginator application (image viewer)
adding images to
animated "loading" images
challenges of loading images dynamically
domkit.js file 2nd
imaginator.html Web page 2nd
modalimg.js file
modalimgkit.css file 2nd
modalimgkit.js file 2nd
modalimgkit_gray.png file 2nd
modalimgkit_wait.gif file 2nd
overview
smokiesXX.jpg files
smokiesXX_thumb.jpg files
testing
user interface
imaginator.html Web page 2nd
IMDb (Internet Movie Database)
Informer application (popup windows)
advantages of popups
ajaxkit.js file
client requests
client/server conversation
domkit.js file
informer.html Web page 2nd
infowinkit.css file 2nd
infowinkit.js file 2nd 3rd
infowinkit_wait.gif file
modifying content of
overview
server responses
skateXXX.html Web pages 2nd
skateXXX.jpg files
testing
user interface
informer.html Web page 2nd
infowinkit.css file
Forecaster application
Informer application 2nd
infowinkit.js file
Forecaster application
Informer application 2nd 3rd
infowinkit_wait.gif file
Forecaster application
Informer application
initForm() function
initInfoWindow() function 2nd
initModal() function 2nd 3rd
initRatings() function 2nd
<input> tag (HTML)
input validation
age validation
Gmail validation
NFL quarterback rating validation
overview
Validator application [See Validator application (input validation).]
INTERACTIVE state (requests)
Internet Movie Database (IMDb)
The Invisible Ad advertisement service
irrational exuberance


J.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

JavaScript
event object
overview
XMLHttpRequest object
abort() method
getAllResponseHeaders() method
getResponseHeader() method
onreadystatechange event
open() method
overrideMimeType() method
overview
readyState property
request lifecycle
responseText property
responseXML property
send() method
setRequestHeader() method
status property
statusText property
Jung, Carl


K.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

Kontera service


L.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

launching Ajax Construction Kit live CD
<li> tag (HTML)
lifecycles of requests
<link> tag (XML)
live CDs
Ajax Construction Kit live CD
backing up data
contents
installing on hard drives
launching
network setup
overview
running as virtual client
running from Web server
running on Mac OS X
running on Windows PCs
tar archives
Live Linux CD
loadBook() function
loadChapter() function
LOADED state (requests)
loadFeed() function
loading
data in small chunks
images dynamically [See Imaginator application (image viewer).]
LOADING state (requests)
loadStockInfo() function
loadStockList() function
logs, server
Lyricsfly.com


M.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

Mac OS X
Maps (Google) 2nd
methods (XMLHttpRequest object)
abort()
getAllResponseHeaders()
getResponseHeader()
open()
overrideMimeType()
send()
setRequestHeader()
Microsoft Remote Scripting technology
modal windows
modalimg.js file
modalimgkit.css file 2nd
modalimgkit.js file 2nd 3rd
modalimgkit_gray.png file 2nd
modalimgkit_wait.gif file 2nd
modprobe command
Mossadegh, Mohammed
movie collection application, creating from Picker application
MySQL database rating systems


N.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

Netflix
networks, configuring for Ajax Construction Kit live CD
news aggregators
News Feeder application [See also RSS news feeds.]
adding news feeds to
ajaxkit.js file
client requests
client/server conversation
creating news feeds
domkit.js file
embedding news feeds in Web pages
files, list of
news aggregators
newsfeeder.css style sheet 2nd
newsfeeder.html Web page 2nd
<body> tag
getElementById() function
handleFeedRequest() function
loadFeed() function
onload event handler
newsfeeder.php server script 2nd
newspaper.gif file
querying news feeds dynamically
server responses
testing
user interface design
wait.gif file
newsfeeder.css style sheet 2nd
newsfeeder.html Web page 2nd
<body> tag
getElementById() function
handleFeedRequest() function
loadFeed() function
onload event handler
newsfeeder.php server script 2nd
newspaper.gif file
nextChapter() function
NFL quarterback rating validator application
nitRatings() function


O.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

objects
Event
XMLHttpRequest
abort() method
getAllResponseHeaders() method
getResponseHeader() method
onreadystatechange event
open() method
overrideMimeType() method
overview
readyState property
request lifecycle
responseText property
responseXML property
send() method
setRequestHeader() method
status property
statusText property
onblur event handler
onkeyup event handler
online shopping carts 2nd
onload event handler
Completer application (auto-completer)
Informer application (popup windows)
News Feeder application
Picker application (stock picker)
Validator application
onreadystatechange event
open() method
Operation Ajax
<option> tag (XML)
Orkut
overrideMimeType() method


P.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

PHP
booker.php script
completer.php server script 2nd
forecaster.php script 2nd 3rd
newsfeeder.php script 2nd
overview 2nd
quoter.php server script
ratingkit.php server script
server.php server script
ziplookup.php server script 2nd
Picker application (stock picker)
client requests
client/server conversation
creating movie collection application from
files
goals of
picker.html Web page 2nd
code listing
handleStockInfoRequest() function
handleStockListRequest() function
loadStockInfo() function
loadStockList() function
onload event handler
replaceText() function
quoter.php server script
server responses
stocks.xml file
testing
user interface
picker.html Web page 2nd
code listing
handleStockInfoRequest() function
handleStockListRequest() function
loadStockInfo() function
loadStockList() function
onload event handler
replaceText() function
popularity of Ajax
popup windows
advantages of
Informer application
client requests
client/server conversation
modifying content of
server responses
testing
user interface
Kontera service
overview
size of
Snap Preview service
weather forecast window (Forecaster application)
ajaxkit.js file
challenges of gathering dynamic weather information
changing city
client requests
client/server conversation
detailed weather reports
domkit.js file
forecaster.html Web page 2nd
forecaster.php server script 2nd 3rd
infowinkit.css file
infowinkit.js file
infowinkit_wait.gif file
overview
server responses
testing
user interface
prevChapter() function
properties of XMLHttpRequest object
readyState
responseText
responseXML
status
statusText
<pubDate> tag (XML)


Q.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

querying news feeds dynamically
quoter.php script
quoter.php server script


R.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

Rater application (rating system)
adding to Web pages
ajaxkit.js file
challenges
changing images in
client requests
client/server conversation
cookiereset.html Web page 2nd
domkit.js file
item IDs
MySQL databases
overview
rater.html Web page 2nd
<body> tag
initRatings() function
<li> tag
setRating() function
<span> tag
<ul> tag
ratingkit.css file 2nd
ratingkit.js file
ratingkit.php server script
server responses
star.gif file
star_sm.gif file
testing
user interface
rater.html Web page 2nd
<body> tag
initRatings() function
<li> tag
setRating() function
<span> tag
<ul> tag
rating systems [See Rater application (rating system).]
ratingkit.css file 2nd
ratingkit.js file 2nd
ratingkit.php server script
readyState property (XMLHttpRequest object)
real-time validation [See input validation.]
real-world applications
Flickr
Google Maps 2nd
Google Suggest
The Invisible Ad advertisement service
Netflix
Really Simple Syndication [See RSS news feeds.]
relationship between Ajax technologies
reloading Web pages
Remote Scripting technology
replaceText() function 2nd 3rd
requests
Booker application
Completer application
Forecaster application
Informer application
lifecycle
News Feeder application
Picker application
Rater application
Shipper application
Validator application
XMLHttpRequest object
abort() method
getAllResponseHeaders() method
getResponseHeader() method
onreadystatechange event
open() method
overrideMimeType() method
overview
readyState property
responseText property
responseXML property
send() method
setRequestHeader() method
status property
statusText property
responses
Booker application
Completer application
Forecaster application
Informer application
News Feeder application
Picker application
Rater application
Shipper application
Validator application
responseText property (XMLHttpRequest object)
responseXML property (XMLHttpRequest object)
restaurant analogy
RSS news feeds
creating
embedding in Web pages
history of
news aggregators
News Feeder application
adding news feeds to
ajaxkit.js file
client requests
client/server conversation
domkit.js file
files, list of
newsfeeder.css style sheet 2nd
newsfeeder.html Web page 2nd
newsfeeder.php server script 2nd
newspaper.gif file
server responses
testing
user interface design
wait.gif file
overview 2nd
querying dynamically
Scientific American Web site
USA Today Web site
running Ajax Construction Kit live CD
installing on hard drives
on Mac OS X
tar archives
as virtual client
from Web server
on Windows PCs


S.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

Scientific American news feeds
scripts
booker.php
completer.php 2nd
forecaster.php 2nd 3rd
newsfeeder.php 2nd
quoter.php
ratingkit.php
server.php server script
ziplookup.php
<select> tag (HTML) 2nd
send() method
server.php server script
servers
conversations [See client/server conversations.]
logs
responses [See responses.]
role of
scripts [See scripts.]
XAMPP server, backing up
setRating() function 2nd
setRequestHeader() method
Shipper application (shipping calculator)
accessing USPS production server
challenge of retrieving live shipping charges
client requests
client/server conversation
overview
server responses
server.php server script
shipper.html Web page
<body> tag
getShipRate() function
handleRequest() function
initForm() function
<select> element
updateTotal() function
testing
user interface
wait.gif image
shipper.html Web page
<body> tag
getShipRate() function
handleRequest() function
initForm() function
<select> element
updateTotal() function
shipping calculator [See Shipper application (shipping calculator).]
shopping carts 2nd
showBiography() function
showInfoWindow() function 2nd 3rd
size of popup windows
skateXXX.html Web pages 2nd
skateXXX.jpg files
smokiesXX.jpg files
smokiesXX_thumb.jpg files
Snap Preview service
snapper.html Web page
<span> tag (HTML)
star.gif file
star_sm.gif file
status property (XMLHttpRequest object)
statusText property (XMLHttpRequest object)
stock picker [See Picker application (stock picker).]
<stock> tag 2nd
stocks.xml file 2nd
strtolower() function
style sheets [See CSS (cascading style sheets).]
Suggest (Google)
Symbol Lookup
synchronicity
Synchronicity


T.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

tags (HTML)
<body>
Completer application
Forecaster application
Imaginator application
informer.html Web page
News Feeder application
Rater application
shipper.html Web page
snapper.html Web page
<head>
<input>
<li>
<select> 2nd
<span>
<ul>
tags (XML)
<bookData>
<channel>
<chapter>
<date>
<description>
<ebook>
<link>
<option>
<pubDate>
<stock> 2nd
<title>
testing
Booker application
Complete application
Forecaster application
Imaginator application
Informer application
News Feeder application
Picker application
Rater application
Shipper application
Validator application
<title> tag (XML)
toolkit
ajaxkit.js file
domkit.js file
infowinkit.js file
modalimgkit.js file
overview
ratingkit.js file
validatekit.js file
TRYNT Movie IMDb Web Service
turning on/off diagnostic bar 2nd


U.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

<ul>, tag (HTML)
UNINITIALIZED state (requests)
updateTotal() function
USA Today news feeds
user interfaces
Completer application
Forecaster application
Imaginator application
Informer application
News Feeder application
Picker application
Rater application
Shipper application
Validator application
USPS Web Tools 2nd
USS Ajax


V.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

validateAge() function
validateDate() function 2nd
validateEmail() function 2nd
validateInteger() function 2nd 3rd
validatekit.js file 2nd
validateNonEmpty() function 2nd
validateNumber() function 2nd
validatePhone() function 2nd
validateZipCode() function 2nd 3rd
validating input [See input validation.]
Validator application (input validation)
ajaxkit.js file
applying validation functions to other user-input forms
client requests
client/server conversation
data types
domkit.js file
overview
server responses
testing
user interface
validatekit.js file
validator.html Web page 2nd
code listing
getCityState() function
getElementById() function
handleCityStateRequest() function
onblur event handler
onload event handler
validateInteger() function
validateZipCode() function
wait.gif file 2nd
ziplookup.php script
ziplookup.php server script
validator.html Web page 2nd
code listing
getCityState() function
getElementById() function
handleCityStateRequest() function
onblur event handler
onload event handler
validateInteger() function
validateZipCode() function
value attribute (<option> tag)
version numbers of Web
viewing images [See Imaginator application (image viewer).]


W.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

wait.gif file 2nd 3rd 4th
The Warriors
weather forecast window [See Forecaster application (weather forecast window).]
Web pages, reloading [See also specific pages (for example, newsfeeder.html).]
Web servers
running Ajax Construction Kit live CD from
XAMPP server, backing up
Web sites
Flickr
Google Maps 2nd
Google Suggest
The Invisible Ad advertisement service
Netflix
Orkut
shopping carts
Web version numbers
webserviceX.net
windows
modal windows
popup windows [See also Imaginator application (image viewer).]
advantages of
Kontera service
overview
size of
Snap Preview service
weather forecast windows [See Forecaster application (weather forecast window).]
Windows, running Ajax Construction Kit live CD on


X.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

XAMPP server, backing up
XML (Extensible Markup Language)
documents
files
overview
tags
<bookData>
<channel>
<chapter>
<date>
<description>
<ebook>
<link>
<option>
<pubDate>
<stock> 2nd
<title>
XML e-books (Booker application)
.xml file extension
XMLHttpRequest object
abort() method
getAllResponseHeaders() method
getResponseHeader() method
onreadystatechange event
open() method
overrideMimeType() method
overview
readyState property
request lifecycle
responseText property
responseXML property
send() method
setRequestHeader() method
status property
statusText property


Y.html

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

Yahoo!'s Symbol Lookup


Z.html

Previous Page

Index

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

ZIP code validator [See Validator application (input validation).]
ziplookup.php server script 2nd

Previous Page